Si të konfiguroni telefonat inteligjentë dhe PC. Portali informativ
  • në shtëpi
  • Hekuri
  • Tregim i qartë i llojit të kolonës. Ndryshimi i kodimit të vargut nga Unicode në ASCII

Tregim i qartë i llojit të kolonës. Ndryshimi i kodimit të vargut nga Unicode në ASCII

Tregon që kolona e re është një kolonë identiteti. Kur shtohet në një tabelë linjë e re motori i bazës së të dhënave gjeneron një vlerë unike vijuese për këtë kolonë. Kolonat e identifikimit zakonisht përdoren me një kufizim PRIMARY KEY për të ruajtur identifikuesit unikë të rreshtave në një tabelë. Vetia IDENTITY mund t'i caktohet kolonave tinyint, smallint, int, bigint, decimal (p, 0) ose numerike (p, 0). Për secilën tabelë mund të krijohet vetëm një kolonë identiteti. Vlerat e parazgjedhura nuk mund të përdoren në kolonën e identitetit. Duhet të specifikohet si vlera fillestare, dhe rrit, ose mos specifikoni asgjë. Nëse asnjë nga vlerat nuk është specifikuar, parazgjedhja është (1,1).

Sintaksë:

[IDENTITETI [(farë, rritje)]

seed - vlera e përdorur për rreshtin e parë të ngarkuar në tabelë.

increment - s vlera e rritjes për t'i shtuar vlerës së identifikuesit të rreshtit të ngarkuar më parë.

[ Orari dhomë] INDENTITETI INT (1, 1) ÇELËSI PRIMAR JO NULL

    Fushat e llogaritura.

Sintaksë:

<имя_столбца> AS <выражение> ]

Një shprehje që specifikon vlerën e një kolone të llogaritur. Një kolonë e llogaritur është një kolonë virtuale që nuk ruhet fizikisht në tabelë, përveç nëse është caktuar flamuri PERSISTED për të. Vlera e kolonës llogaritet bazuar në një shprehje që përdor kolona të tjera në të njëjtën tabelë.

Për shembull, një përkufizim i llogaritur i kolonës mund të jetë si më poshtë:

Kostoja e mallrave AS Çmimi për një * sasi.

Një shprehje mund të jetë një emër kolone jo e llogaritur, konstante, funksion, ndryshore ose ndonjë kombinim i tyre, i lidhur nga një ose më shumë operatorë. Shprehja nuk mund të jetë një nënpyetje ose të përmbajë pseudonime të tipit të të dhënave.

Kolonat e llogaritura mund të përdoren në listat e përzgjedhura, klauzolat WHERE, ORDER BY klauzolat dhe kudo tjetër ku mund të përdoren shprehjet e rregullta, me përjashtim të rasteve të mëposhtme.

Një kolonë e llogaritur nuk mund të përdoret si një përkufizim i një kufizimi DEFAULT ose FOREIGN KEY, ose në lidhje me një përkufizim NOT NULL. Megjithatë, një kolonë e llogaritur mund të përdoret si një kolonë kyçe indeksi ose si pjesë e një kufizimi PRIMARY KEY ose UNIQUE nëse vlera e kolonës së llogaritur përcaktohet nga një shprehje përcaktuese (e parashikueshme) dhe lloji i të dhënave të rezultatit lejohet në kolonat e indeksit. .

Për shembull, nëse tabela përmban kolona me numra të plotë a dhe b, kolona e llogaritur a + b mund të përfshihet në indeks dhe në kolonën e llogaritur a + DATEPART (dd, GETDATE ())- nuk mundet, pasi vlera e tij mund të ndryshojë në thirrjet pasuese.

Një kolonë e llogaritur nuk mund të jetë kolona e synuar e një deklarate INSERT ose UPDATE.

DBMS përcakton automatikisht anulimin për kolonat e llogaritura bazuar në shprehjet e përdorura. Supozohet se rezultati i shumicës së shprehjeve është i pavlefshëm, edhe nëse përdoren vetëm kolonat që nuk janë të anulueshme, pasi një tejmbushje e mundshme ose humbja e saktësisë mund të rezultojë në një vlerë nule. Për të zbuluar nëse një kolonë e llogaritur e një tabele mund të jetë nule, përdorni funksionin COLUMN PROPERTY me veçorinë AllowsNull... Sigurohuni që shprehja të mos lejojë vlerat zero, mundeni duke specifikuar ISNULL me konstanten kontroll_shprehje ku konstante është një vlerë jozero, duke zëvendësuar çdo vlerë NULL. Kolonat e llogaritura të bazuara në shprehje që përmbajnë CLR UDT kërkojnë leje REFERENCash për llojin.

Tregon se komponenti SQL Server do të ruajë fizikisht vlerat e llogaritura në tabelë dhe do t'i përditësojë ato sa herë që ndryshon çdo kolonë nga e cila varet kolona e llogaritur. Specifikimi i PERSISTED në një kolonë të llogaritur ju lejon të krijoni një indeks në kolonën e llogaritur që është përcaktues, por i pasaktë.

duke krijuar një tabelë Përveç teknikave të diskutuara, mund të specifikoni fjalën kyçe opsionale CONSTRAINT për t'i dhënë kufizimit një emër që është unik brenda bazës së të dhënave.

KRIJONI T TË GJITHSHËM Porositë(

ID_UrdhëriINT NUK NULL ,

Gjellë INT JO NULL,

sasi_ porcione KONTROLLI JO NULL ( sasi_ porcione >0 ) ,

datë DATA JO NULLE ,

ÇELESI PRIMAR ( ID_Urdhëri, Gjellë, datë),

KUFIZIMI FOREIGN_KEY

ÇELËSI I HUAJ ( Gjellë, datë) REFERENCAT Menu( Gjellë, datë)) ;

Pastaj mund të punoni me kufizimin e emërtuar si me një objekt të bazës së të dhënave. Nëse emri i kufizimit nuk specifikohet, motori DBMS do ta krijojë atë automatikisht, duke zgjedhur emrin sipas rregullave të përcaktuara në sistem.

Një shembull i një skripti të ndërtuar nga sistemi për të krijuar tabelën Dish_view_view

KRIJO TABELE. [Dish_type_reference] (

IDENTITETI (1,1) JO NULL,

[Shiko] (20) JO NULL,

ÇELËSI PRIMAR I KUFIZIMIT I GRUPTUAR

) ME (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) AKTIV

Ju keni parë disa nga konventat e konfigurimit që përdor kjo qasje. Në veçanti, keni parë se si të personalizoni modelin e entitetit duke përdorur shënimet e të dhënave të shprehura përmes atributeve C # dhe duke përdorur Fluent API. Në këtë dhe artikujt pasues, ne do t'i hedhim një vështrim më të afërt këtyre mënyrave për të personalizuar modelin e të dhënave.

Personalizimi i llojeve të kolonave

Më parë, kur shikonit rastin e përdorimit të Code-First, tashmë keni parë përdorimin e disa atributeve të meta të dhënave që ju lejuan të personalizoni llojin e të dhënave të një kolone në një tabelë të bazës së të dhënave dhe të aplikoni kufizime për të (për shembull, duke specifikuar nëse ajo mbështet vlerat null). Ne do t'i shikojmë këto atribute në më shumë detaje më poshtë.

Kufizimi i gjatësisë

Tabela më poshtë tregon konventat për kufizimin e gjatësive të kolonave, se si ato shënohen dhe zbatohen në Fluent API:

Kufizimi i gjatësisë mund të vendoset në vargje ose vargje bajt. Sipas konventës, Code-First përdor vetëm kufizimin e gjatësisë maksimale, që do të thotë se SQL Server vendos llojin e të dhënave për vargjet dhe vargjet e bajteve në NVARCHAR (n) dhe VARBINARY (n), ku n është gjatësia e specifikuar në kufizim. Si parazgjedhje, nëse nuk është aplikuar asnjë kufizim gjatësie për veçoritë e modelit, Code-First do të vendosë gjatësinë maksimale të mundshme të kolonës në NVARCHAR (maksimum) dhe VARBINARY (maksimum).

Siç tregohet në tabelë, duke përdorur shënimet e të dhënave, mund të vendosni gjatësinë minimale për një tipar model duke përdorur atributin MinLength - ky kufizim nuk do të ndikojë në asnjë mënyrë në tabelën e bazës së të dhënave. (Siç u përshkrua më herët, atributet e meta të dhënave mund të përdoren jo vetëm në Entity Framework, por, për shembull, edhe në vërtetimin e modelit ASP.NET.) Kjo është arsyeja pse metoda HasMinLength () mungon në API-në Fluent, pasi kjo API është pjesë e Kornizës së Entitetit dhe është përgjegjëse për vendosjen e konventave vetëm për kodin e parë.

Vlen të përmendet se ju mund të specifikoni gjatësinë maksimale dhe minimale të fushës në një atribut StringLength duke përdorur parametrat e emërtuar të këtij atributi. V shembullin e mëposhtëm tregon përdorimin e kufizimeve të gjatësisë duke përdorur shënime (këtu po përdorim shembullin e modelit që krijuam në artikullin "Përdorimi i kodit të parë" më parë):

Përdorimi i Sistemit; duke përdorur System.Collections.Generic; duke përdorur System.ComponentModel.DataAnnotations; Hapësira e emrit KodiFirst (klasa publike Klienti (int publik CustomerId (merr; vendos;) varg publik Emri (merr; vendos;) varg publik Mbiemri (merr; vendos;) varg publik Email (merr; vendos;) publik int Mosha (merr; vendos ;) bajt publik Foto (merr; vendos;) // Lidhja me listën publike virtuale të porosive Porositë (merr; vendos;)) klasë publike Porosi (int publik OrderId (merr; vendos;) varg publik Emri i produktit (merr; vendos;) varg publik Përshkrimi (merr; vendos;) int publik Sasia (merr; vendos;) publik DataTime PurchaseDate (merr; vendos;) // Lidhja me blerësin publik Klienti Klient (merr; vendos;)))

Dhe në kodin e mëposhtëm vendosje të ngjashme kryhet duke përdorur Fluent API (mos harroni se për të përdorur këtë API, duhet të anashkaloni metodën e konfigurimit OnModelCreating () në klasën e kontekstit, e cila në shembullin tonë është klasa SampleContext):

() .Properti (c => c.Emri) .HasMaxLength (30); ModelBuilder.Entiteti () .Prona (c => c.Email) .HasMaxLength (100); ModelBuilder.Entiteti () .Property (o => o.Emri i produktit) .HasMaxLength (500); )

Duke specifikuar në mënyrë eksplicite llojin e një kolone

Siç u përshkrua më parë, Entity Framework harton automatikisht llojet e të dhënave të modelit me llojet e të dhënave në përputhje me SQL. Code-First ju lejon të manipuloni këtë proces për të specifikuar në mënyrë eksplicite llojin e të dhënave për një kolonë, siç tregohet në shembullin më poshtë:

Klienti i klasës publike (publik int CustomerId (merr; vendos;) // ... bajt publik Foto (merr; vendos;) // ...) // e njëjta gjë me Fluent API të mbrojtura nga anulimi i zbrazët OnModelCreating (DbModelBuilder modelBuilder) (modelBuilder. Entitet () .Property (c => c.CustomerId) .HasColumnType ("smallint"); ModelBuilder.Entiteti () .Property (c => c.Foto) .HasColumnType ("imazh"); )

Mbështetja e kolonës NULL

Konventa e Mbështetjes Nullore të Kornizës së Entitetit në një kolonë tabele thotë se të gjitha llojet .NET që mbështesin vlerat null (objektet) janë të lidhura me llojet e SQL me një deklaratë të qartë NULL, dhe anasjelltas, llojet .NET që nuk mbështesin null (strukturat) janë të lidhura me llojet SQL me një deklaratë të qartë NOT NULL.

Për të treguar qartë se një lloj i të dhënave nuk duhet të mbështesë vlera null, duhet të përdorni atributin Required në modelin e të dhënave ose të përdorni metodën IsRequired () të objektit të konfigurimit në Fluent API. Për të treguar në mënyrë të qartë përkundrazi se lloji i të dhënave duhet të mbështesë vlerat NULL, duhet të përdorni koleksionin Nullable ose përdorni sintaksën C #, e cila për llojet e vlerave që mbështesin null përfshin një pikëpyetje pas atij lloji (për shembull, int?).

Shembulli i mëposhtëm tregon se si të përdoren këto cilësime për të konfiguruar informacionin rreth llojeve të zhvlerësueshme ose jo të zhvlerësueshme në një tabelë të bazës së të dhënave:

Klasa publike Customer (public int CustomerId (get; set;) string publik FirstName (get; set;) string publik Mbiemri (merr; vendos;) // Kjo fushë mund të jetë NULL, // pasi ne kemi specifikuar në mënyrë eksplicite llojin int? mosha (merr; vendos;) // Ngjashëm me pronën e mëparshme publike Nullable Mosha 1 (merr; vendos;) // ...) // e njëjta gjë me Fluent API e mbrojtur nga anulimi i pavlefshëm OnModelCreating (DbModelBuilder modelBuilder) (modelBuilder.Entity () .Properti (c => c.Emri) .IsRequired (); ModelBuilder.Entiteti () .Properti (c => c.Mbiemri) .IsRequired (); )

Vini re se vetëm mbështetja NOT NULL për llojet e të dhënave të referencës mund të konfigurohet në Fluent API dhe mbështetja NULL nuk mund të konfigurohet për llojet e vlerave, pasi Mbështetja NULL për to specifikohet në mënyrë eksplicite kur deklarohet lloji i pronës në klasën e modelit.

Vendosja e çelësave kryesorë

Korniza e entitetit kërkon që çdo klasë e modelit të entitetit të ketë një çelës unik (sepse për secilën tabelë në bazë relacionale të dhënat, duhet të përdoret çelësi primar). Ky çelës përdoret në objektin e kontekstit për të gjurmuar ndryshimet në objektet e modelit. Code-First bën disa supozime kur kërkon një çelës në një tabelë. Për shembull, kur krijuam bazën e të dhënave për klasat e entitetit Klient dhe Porosit më herët, kur shikonim qasjen Code-First, Entity Framework shënoi fushat CustomerId dhe OrderId në tabela si çelësa kryesorë dhe i vendosi ato që të mbështesin lloje jo të anulueshme :

EF gjithashtu shtoi automatikisht mbështetjen e rritjes automatike në këto fusha (mos harroni se në T-SQL kjo bëhet duke përdorur deklaratën IDENTITY). Më shpesh, çelësat kryesorë në një bazë të dhënash janë të tipit INT ose GUID, edhe pse të tillë tip primitiv mund të përdoret si çelës primar. Një çelës primar në një bazë të dhënash mund të përbëhet nga kolona të shumta tabele, në mënyrë të ngjashme, një çelës modeli i entitetit EF mund të përbëhet nga veti të shumta të modelit. Do të shihni më vonë se si të vendosni çelësat e përbërë.

Vendosja e qartë e çelësave primar

Në rastin e dy klasave tona, Klientit dhe Porosit, nuk ka nevojë të shqetësoheni për specifikimin e qartë të çelësit primar, pasi ne përdorim vetitë CustomerId dhe OrderId, të cilat ndjekin konventën e emërtimit të çelësit "+ Id". Le të shohim një shembull ku duhet të specifikoni në mënyrë eksplicite një çelës primar. Shtoni klasën e mëposhtme të thjeshtë në skedarin tuaj të modelit:

Projekti i klasës publike (identifikuesi publik i udhëzuesit (merr; vendos;) publik DataTime Data e fillimit (merr; vendos;) publike DataTime Data e përfundimit (merr; vendos;) Kosto publike dhjetore (merr; vendos;))

Qëllimi ynë është të tregojmë se vetia Identifier në këtë klasë është çelësi kryesor i tabelës. Siç mund ta shihni, emri i kësaj prone nuk ndjek konventën e emërtimit të çelësit kryesor të Entity Framework.

Shtoni një përshkrim të tabelës së re në klasën e kontekstit SampleContext:

Klasa publike SampleContext: DbContext (// ... publike DbSet Projektet (merr; vendos;) // ...)

Tani, nëse ekzekutoni aplikacionin tonë dhe futni të dhënat e një klienti të ri, një përjashtim do të hidhet në klasën DbModelBuilder, për faktin se nuk mund të ndërtojë saktë modelin e të dhënave të entitetit. (Për kujtesë, aplikacioni ynë është një faqe e thjeshtë ASP.NET me aftësinë për të futur një klient të ri.)

Ky përjashtim është shkaktuar nga Entity Framework që nuk gjen një pronë të quajtur Id ose ProjectId në tabelën e Projektit dhe Code-First nuk mund të kuptojë se cilën fushë të përdorë si çelësin kryesor të tabelës. Ky problem mund të korrigjohet duke përdorur shënimet e të dhënave ose Fluent API, siç tregohet në shembullin më poshtë:

Projekti i klasës publike (Identifikuesi publik i udhëzuesit (merr; vendos;) publik DateTime Data e fillimit (merr; vendos;) publike DateTime Data e përfundimit (merr; vendos;) Kostoja publike dhjetore (merr; vendos;)) // e njëjta gjë me anulimin e mbrojtur nga API Fluent OnModelCreating (DbModelBuilder modelBuilder) (modelBuilder.Entity () .HasKey (p => p.Identifikuesi); )

Ju lutemi vini re se kur përdorni Fluent Metoda API HasKey () specifikohet pas thirrjes së metodës Entity () dhe jo pas thirrjes së Entitetit () .Prona (), siç u bë në shembujt e mësipërm, pasi çelësi primar vendoset në nivelin e tabelës, jo në nivelin e vetive.

Konfigurimi i rritjes automatike për çelësat kryesorë

Siç mund ta shihni nga tabela, sipas konventave, Entity Framework specifikon rritjen automatike për vetitë int. Në tabelën e projektit të krijuar më parë, lloji Guid është specifikuar për çelësin primar, si rezultat, EF nuk përdor një numërues për këtë fushë kur krijon një tabelë në bazën e të dhënave. Kjo është treguar në figurë:

Le të shtojmë një formë të re ueb në projektin tonë, të cilin do ta quajmë DatabaseGenerated.aspx. Në trajtuesin Page_Load, shtoni kodin e mëposhtëm ku shtojmë të dhëna të reja në tabelën e Projektit. V në këtë rast këto të dhëna do të shtohen sa herë që hapim faqen tonë të formularit të internetit në një shfletues.

Përdorimi i Sistemit; duke përdorur System.Data.Entity; duke përdorur CodeFirst; hapësira e emrit ProfessorWeb.EntityFramework (klasa publike e pjesshme DatabaseGenerated: System.Web.UI.Page (mbrojtur void Page_Load (dërguesi i objektit, EventArgs e) (// Ky cilësim nevojitet në mënyrë që baza e të dhënave të fshihet automatikisht // dhe të rikrijohet kur struktura është ndryshuar modele // (për ta bërë më të lehtë testimin e shembujve) Database.SetInitializer (i ri DropCreateDatabaseIfModelChanges ()); SampleContext kontekst = SampleContext i ri (); Projekti i projektit = Projekti i ri (Data e fillimit = DataTime.Tani, Data e Fundit = DataTime.Tani.AddMonths (1), Kostoja = 8000M); konteksti.Projektet.Shto (projekt); konteksti.RuajNdryshimet (); )))

Ekzekutoni projektin dhe hapni formularin e internetit DatabaseGenerated.aspx. Si rezultat, një rekord i ri do të shtohet në tabelën e Projektit:

As baza e të dhënave dhe as Entity Framework nuk e dinë se ne do të dëshironim të krijonim një Udhëzues të ri për çdo regjistrim të ri, kështu që një ID që përmban të gjitha zerat do të gjenerohet automatikisht. Nëse rifreskoni faqen në shfletues (në fakt, në këtë rast, kodi do të përpiqet të fusë hyrje e re në tabelë), atëherë Entity Framework do të kthejë një SqlException, i cili hidhet sepse po përpiqemi të fusim një rekord me një identifikues që ekziston tashmë në tabelë, d.m.th. në këtë rast, aktivizohet kufizimi kryesor i çelësit - ai duhet të jetë unik për çdo rekord të ri.

Si rezultat, për të vendosur ky problem, do të na duhet të gjenerojmë një Udhëzues unik në kod. Tabelat që përdorin shtimin automatik për çelësat kryesorë nuk e kanë këtë punë shtesë. për çdo rekord të ri të futur, numëruesi krijon një vlerë të re për çelësin primar duke marrë vlerën e çelësit primar për rekordin e fundit dhe duke shtuar 1 në të (nëse është përdorur IDENTITY (1,1)).

Për të zgjidhur këtë problem për çelësat e tipit të ndryshëm nga int, duhet të përdorni atributin DatabaseGenerated metadata, në konstruktorin e të cilit specifikoni DatabaseGeneratedOption Numeration duke pasur tre kuptimet e mundshme:

Asnje

Baza e të dhënave nuk gjeneron ndonjë vlerë unike për çelësin primar. Në fakt, duke përdorur këtë opsion, mund të çaktivizoni shtimin automatik të rritjes automatike në çelësat kryesorë të tipit int.

Identiteti

Kur futni vlera në një tabelë, baza e të dhënave do të krijojë vlerë unike për çelësin primar.

I llogaritur

Ngjashëm me Identity, me përjashtimin e vetëm që çelësi primar do të gjenerohet jo vetëm kur të dhënat futen në tabelë, por edhe kur ato përditësohen.

Modifikoni klasën e modelit për të udhëzuar bazën e të dhënave për të krijuar një çelës primar unik:

Projekti i klasës publike (identifikuesi publik i udhëzuesit (merr; vendos;) publik DataTime Data e fillimit (merr; vendos;) publike DataTime Data e përfundimit (merr; vendos;) Kosto publike dhjetore (merr; vendos;))

Ekzekutoni projektin e mostrës dhe rifreskoni faqen disa herë për të futur shumë regjistrime në tabelë dhe sigurohuni që përjashtimi të mos hidhet më. Figura më poshtë tregon të dhënat e shtuara në tabelë:

Kushtojini vëmendje ID-ve të krijuara automatikisht për projektet. I njëjti efekt mund të arrihet duke përdorur metodën HasDatabaseGeneratedOption () në Fluent API:

Zvogëlimi i mbrojtur i zbrazët OnModelCreating (DbModelBuilder modelBuilder) (modelBuilder.Entity () .Property (p => p.Identifikuesi) .HasDatabaseGeneratedOption (DatabaseGeneratedOption.Identity); )

Puna me lloje komplekse të të dhënave

Entity Framework ka mbështetur aftësinë për të përdorur lloje komplekse që nga versioni i parë. Në fakt, një lloj kompleks në .NET është një klasë që mund të referohet në një klasë modeli. Një lloj kompleks nuk ka çelës dhe mund të përdoret në shumë objekte në një model. Le të marrim një shembull të modelit të mëposhtëm:

Klasa publike Përdoruesi (int publik UserId (merr; vendos;) publik int SocialNumber (merr; vendos;) varg publik Emri (merr; vendos;) varg publik Mbiemri (merr; vendos;) varg publik Adresa e rrugës (merr; vendos;) publike Qyteti i vargut (merr; vendos;) vargun publik ZipCode (merr; vendos;))

Në këtë klasë, adresa e vendbanimit të përdoruesit mund të dallohet në klasë të veçantë dhe për t'iu referuar asaj:

Klasa publike Përdoruesi (int publik Id i përdoruesit (merr; vendos;) int publik Numri social (merr; vendos;) varg publik Emri (merr; vendos;) varg publik Mbiemri (merr; vendos;) adresa publike Adresa (merr; vendos;)) Adresa e klasës publike (int publik AddressId (merr; vendos;) varg publik Adresa e rrugës (merr; vendos;) varg publik Qyteti (merr; vendos;) varg publik ZipCode (merr; vendos;))

Sipas marrëveshjes, Entity Framework do ta analizojë këtë model si dy tabela të veçanta. Por qëllimi ynë është të krijojmë një tip kompleks nga klasa Adresa. Mënyra tradicionale për të krijuar një lloj kompleks nga klasa Adresa prezanton heqjen e AddressId:

Adresa e klasës publike (// publike int AddressId (merr; vendos;) varg publik Adresa e rrugës (merr; vendos;) varg publik Qyteti (merr; vendos;) varg publik ZipCode (merr; vendos;))

Përveç rregullit që një tip kompleks nuk duhet të ketë çelës, Code-First imponon dy rregulla të tjera që duhen ndjekur për të zbuluar një lloj kompleks. Së pari, një lloj kompleks duhet të përmbajë vetëm veti të thjeshta. Së dyti, një klasë që përdor këtë lloj nuk lejohet të specifikojë një lloj koleksioni për një tipar të tipit kompleks. Me fjalë të tjera, nëse dëshironi të përdorni llojin kompleks Address në klasën User, atëherë një veti e këtij lloji nuk duhet të shënohet si Listë.

ose përdorni një koleksion tjetër.

Siç tregohet në imazhin më poshtë, pas ekzekutimit të aplikacionit, Code-First njeh llojin kompleks dhe krijon fusha të personalizuara në tabelën e Përdoruesit (mos harroni të shtoni deklaratën e përdoruesit në klasën e kontekstit):

Vini re se si emërtohen fushat që përshkruajnë adresën e përdoruesit: ComplexTypeName_PropertyName. Kjo është konventa e emërtimit të Kornizës së Entitetit për llojet komplekse.

Përshtatja e llojeve komplekse Duke anashkaluar konventat e kodit të parë

Po nëse klasa juaj e tipit kompleks nuk ndjek konventat e Entity Framework, për shembull, dëshironi të përdorni fushën AddressId në klasën Adresa? Nëse tani e shtojmë këtë fushë në klasën Adresa dhe e ekzekutojmë projektin, atëherë në vend të një tabele Përdoruesi dhe një lloji kompleks Adrese, Entity Framework do të krijojë dy tabela të lidhura me njëra-tjetrën me një çelës të huaj. Për të zgjidhur këtë problem, mund të specifikoni në mënyrë eksplicite Atributi ComplexType në klasën e modelit ose përdorimin Metoda ComplexType (). klasa DbModelBuilder në Fluent API:

Adresa e klasës publike (int publik AddressId (merr; vendos;) varg publik Adresa e rrugës (merr; vendos;) varg publik Qyteti (merr; vendos;) varg publik ZipCode (merr; vendos;)) // e njëjta gjë me Fluent API e mbrojtur nga anulimi i pavlefshëm OnModelCreating (DbModelBuilder modelBuilder) (modelBuilder.ComplexType

(); }

U tha më lart se një klasë që përshkruan një lloj kompleks duhet të ketë vetëm veti të thjeshta (d.m.th., duke mos iu referuar objekteve të tjera). Kjo marrëveshje mund të kapërcehet duke përdorur të gjitha mjetet e njëjta. Më poshtë është një shembull në të cilin është shtuar një lloj i ri kompleks UserInfo duke iu referuar një lloji tjetër FullName:

Klasa publike Përdoruesi (public int UserId (get; set;) public UserInfo UserInfo (get; set;) public Adresa Adres (get; set;)) class public UserInfo (public int SocialNumber (get; set;) // Veti jo e thjeshtë publik Emri i plotë Emri i plotë (merr; vendos;)) klasë publike Emri i plotë (vargu publik Emri (merr; vendos;) varg publik Mbiemri (merr; vendos;)) klasë publike Adresa (int publik AdresaId (merr; vendos;) varg publik Adresa e rrugës ( marr; vendos;) varg publik Qyteti (merr; vendos;) varg publik ZipCode (merr; vendos;))

Duke udhëzuar Code-First që UserInfo është një lloj kompleks duke përdorur atributin ComplexType, ne kemi kapërcyer kufizimin e llojeve komplekse duke përdorur konventën e paracaktuar.

Vlen të përmendet se Code-First ju lejon të personalizoni lloje komplekse ashtu si tabelat e zakonshme duke përdorur Fluent API ose shënime. Më poshtë është një shembull për konfigurimin e një Adrese të llojit kompleks:

Adresa e klasës publike (int publik AddressId (merr; vendos;) varg publik Adresa e rrugës (merr; vendos;) varg publik Qyteti (merr; vendos;) varg publik ZipCode (merr; vendos;)) // e njëjta gjë me Fluent API e mbrojtur nga anulimi i pavlefshëm OnModelCreating (DbModelBuilder modelBuilder) (modelBuilder.ComplexType

() .Prona (a => a.Adresa e rrugës) .HasMaxLength (100); )

Figura më poshtë tregon strukturën e tabelës së Përdoruesit. Këtu mund të shihni se si EF emërton vetitë e llojeve komplekse me referenca brenda dhe se si EF vendos një kufizim në fushën StreetAddress:

Përshkrimi i cilësimeve të tjera

Në këtë seksion, ne do të shqyrtojmë shkurtimisht të gjitha cilësimet e mbetura të kolonës së tabelës, të cilat përdoren rrallë për shkak të veçorive të tyre specifike.

Kolonat e vulave kohore

Lloji i të dhënave TIMESTAMP në T-SQL specifikon një kolonë që përkufizohet si VARBINARE (8) ose BINARE (8), në varësi të vetive të kolonës, të jetë NULL. Për secilën bazë të dhënash, sistemi përmban një numërues që rritet sa herë që futet ose përditësohet ndonjë rresht që përmban një qelizë TIMESTAMP dhe i caktohet asaj qelize vlerën e dhënë... Kështu, duke përdorur qelizat e tipit TIMESTAMP, mund të përcaktoni kohën relative ndryshimi i fundit rreshtat përkatës të tabelës. (ROWVERSION është sinonim i TIMESTAMP.)

Në vetvete, vlera e ruajtur në një kolonë TIMESTAMP nuk është e rëndësishme. Kjo kolonë përdoret zakonisht për të përcaktuar nëse një rresht specifik në një tabelë ka ndryshuar që nga hera e fundit që është aksesuar. Kjo lejon qasjen e njëkohshme në një tabelë të bazës së të dhënave për t'u adresuar duke lejuar thread-ët e tjerë të bllokohen nëse filli aktual ka ndryshuar vlerat me radhë.

Në Code-First, për të treguar se një kolonë duhet të jetë e tipit TIMESTAMP, duhet të përdoret i njëjti emër Atributi i vulës kohore në shënime ose Metoda IsRowVersion (). në Fluent API siç tregohet në shembullin më poshtë:

Bajt publik RowVersion (merr; vendos;) // e njëjta gjë me Fluent API të mbrojtura nga anulimi i pavlefshëm OnModelCreating (DbModelBuilder modelBuilder) (modelBuilder.Entity () .Property (p => p.RowVersion) .IsRowVersion (); )

Një mënyrë më pak e zakonshme për të qenë të sigurt kur punoni me fije paralele është të specifikoni një kontroll të konkurencës për secilën kolonë. Kjo metodë mund të përdoret ende në DBMS që nuk mbështesin llojet e vulave kohore / Rowversion. Kur punon në këtë mënyrë, thread-i nuk kontrollon nëse rekordi në tabelë ka ndryshuar, por thjesht bllokon aksesin në të për thread-ët e tjerë derisa të përfundojë procesin e shkrimit. Për të specifikuar kolonat për të kaluar kontrollin e konkurencës, përdorni Atributi ConcurrencyCheck në shënime, ose Metoda IsConcurrencyToken (). në Fluent API.

Ndryshimi i kodimit të vargut nga Unicode në ASCII

Si parazgjedhje, Entity Framework do të konvertojë gjithçka llojet e vargjeve modeloni të dhëna të tilla si varg ose char në llojet e të dhënave të vargut SQL që përdorin kodimin e Unicode me dy bajt NVARCHAR ose NCHAR. Mund ta ndryshoni këtë sjellje për t'i thënë në mënyrë eksplicite EF që të përdorë kodimin ASCII me një bajt - VARCHAR dhe CHAR do të përdoren në përputhje me rrethanat. Për ta bërë këtë, ju duhet të përdorni Metoda IsUnicode (). me një parametër boolean të kaluar tek ai në Fluent API. Shënimet nuk ofrojnë aftësinë për të personalizuar kodimin e vargjeve.

Specifikimi i saktësisë për një tip dhjetor

Ju mund të përdorni Metoda HasPrecision (). me dy parametra të kaluar, i cili përdoret në Fluent API. Shënimet e të dhënave në Code-First nuk ofrojnë një alternativë ndaj kësaj metode. Si parazgjedhje, Entity Framework vendos saktësinë në 18 dhe shkallën në 2 për llojet dhjetore.

Shembulli i mëposhtëm tregon përdorimin e kësaj metode për veçorinë Kosto të tabelës së Projektit që kemi krijuar më parë kur shikonim çelësat kryesorë:

Zvogëlimi i mbrojtur i zbrazët OnModelCreating (DbModelBuilder modelBuilder) (modelBuilder.Entity () .Prona (p => p.Kosto) .Ka Precision (6, 3); )

Çfarë është IDENTITETI

IDENTITY nuk është një lloj i të dhënave. Kjo është një veçori shtesë, një kufizim i vendosur në llojet e të dhënave të plota në MS SQL Server. ato. kjo veçori mund të aplikohet në fushat e llojeve të mëposhtme: i vogël, i imët, ndër, bigint, dhjetore (p, 0), ose numerike (p, 0)

Analogu i FoxPro i kësaj vetie është lloji i të dhënave Integer-AutoIncrement. Vetëm mos supozoni se Integer-AutoIncrement është fusha me veçorinë Identity. Aspak. Ky është pikërisht analogu. Ato janë kryesisht të ngjashme, por kanë një numër dallimesh. Ky artikull do të fokusohet në vetinë IDENTITY në serverin MS SQL.

Fushat me veçorinë IDENTITY kanë karakteristikat e mëposhtme:

  • Vetëm një fushë me veçorinë IDENTITY mund të ekzistojë në një tabelë.
  • Një fushë me veçorinë IDENTITY nuk mund të modifikohet. Ato janë vetëm për lexim.
  • Vlera për fushën me vetinë IDENTITY caktohet automatikisht kur krijohet një rekord i ri.

Ka disa veçori të tjera, por ato tashmë janë pasojë e veçorive të listuara.

Vlera e re është vlera e fundit e përdorur plus një vlerë fikse. Vini re se vlera e re nuk bazohet në vlerën maksimale në të dhënat ekzistuese, dhe sipas vlerës së fundit të përdorur. Kjo do të thotë që të dhënat me vlerën e fundit të përdorur mund të mos ekzistojnë fizikisht, megjithatë, kjo vlerë do të përdoret.

Me fjalë të tjera, vrimat në sekuencën e vlerave të fushës me vetinë IDENTITY janë krejtësisht të pranueshme. Lista e kuptimeve nuk është aspak e vazhdueshme

Në mënyrë tipike, 1 specifikohet si rritje, por mund të jetë çdo numër i plotë. Përfshirë negative.

Për shkak të kësaj natyre të fushave me vetinë IDENTITY, fusha të tilla shpesh përdoren si çelësa kryesorë. Me fjalë të tjera, si fusha, me vlerën e të cilave gjithmonë mund të identifikoni në mënyrë unike një rekord tabele.

Vini re se vetia IDENTITY nuk ka kontroll mbi veçantinë e të dhënave. Për shembull, nëse fusha ishte fillimisht e llojit INTEGER, dhe një numër vlerash ishin futur në të. Dhe më pas struktura e tabelës u ndryshua, dhe vetia IDENTITY u imponua në këtë fushë, atëherë regjistrimet e reja mund të kenë të njëjtat të dhëna që ishin futur tashmë më herët në këtë tabelë. Prandaj, nëse një fushë me veçorinë IDENTITY përdoret si çelës primar, atëherë duhet të vendoset një kufizim shtesë unike në këtë fushë.

Disavantazhi i përdorimit të fushave me vetinë IDENTITY si çelës primar

Megjithatë, pavarësisht nga avantazhet e qarta të përdorimit të fushave me veçorinë IDENTITY si çelës primar, ato kanë gjithashtu një pengesë serioze.

Vlera e fushave me vetinë IDENTITY nuk mund të dihet derisa të krijohet fizikisht rekordi.

Edhe çfarë? Cilat janë problemet? Le të krijojmë një rekord dhe të zbulojmë vlerën e re të tij.

Problemi është se për të gjetur vlerën e një fushe të çdo rekord, fillimisht duhet gjetur ky rekord. Dhe kërkimi për një rekord kryhet vetëm nga vlera e çelësit primar. Ai, kuptimi i të cilit duhet të përcaktohet. Një rreth vicioz: për të lexuar një vlerë, duhet ta dini këtë vlerë!

Struktura e ruajtjes së të dhënave në serverin MS SQL është thelbësisht e ndryshme nga struktura e ruajtjes së të dhënave në skedarët DBF. Ai nuk përmban koncepte të tilla si " numri fizik regjistron "," rekordin tjetër "," rekordin e fundit ", etj. Kjo do të thotë, është e pamundur të shkosh te" rekordi i fundit "për të lexuar vlerën e çelësit të tij primar.

Për më tepër, edhe pse vlera e re e fushës me vetinë IDENTITY është gjithmonë më e madhe se cilado prej vlerat ekzistuese(nëse rritja është numër pozitiv), por është gjithashtu e pamundur të përcaktohet kjo vlerë e re thjesht duke llogaritur maksimumin e vlerave ekzistuese. Jo, vetë vlera maksimale, natyrisht, do të merret. Thjesht nuk ka asnjë garanci që vlera që rezulton është vlera e regjistrimit të saktë që është krijuar.

Çështja është se, si rregull, serveri MS SQL përdoret në aplikacione me shumë përdorues. Kjo do të thotë që disa përdorues mund të krijojnë rekorde të reja në të njëjtën kohë. Rezulton se një përdorues krijoi një rekord të ri, më pas filloi të llogaritte vlerën maksimale dhe në atë moment një përdorues tjetër gjithashtu krijoi një rekord të ri. Si rezultat, përdoruesi i parë si vlera maksimale do të marrë vlerën e hyrjes së krijuar nga përdoruesi i dytë.

Pra, a duhet të ndalojmë përdorimin e fushave me vetinë IDENTITY si çelës kryesor? Aspak. Megjithatë, ka mënyra për të përcaktuar vlerën e një fushe me vetinë IDENTITY të një rekordi të ri.

Si të përcaktohet vlera e një fushe me vetinë IDENTITY në një rekord të ri

Në fakt, ekzistojnë tre strategji themelore për përcaktimin e vlerës së një fushe me vetinë IDENTITY në një rekord të ri, të sapokrijuar.

Tani le të hedhim një vështrim më të afërt në avantazhet dhe disavantazhet e secilës strategji.

Vlera e kthyer nga ndryshorja e sistemit @@ IDENTITY

Ekzistojnë një numër variablash të sistemit në serverin MS SQL, vlera e të cilave ndryshon automatikisht kur ndodhin ngjarje të caktuara. Në veçanti, ndryshorja e sistemit @@ IDENTITY vendoset automatikisht në vlerën e fushës IDENTITY të rekordit të fundit të krijuar në lidhjen aktuale. ato. krijimi i regjistrimeve të reja në një lidhje tjetër (nga një përdorues tjetër) nuk do të ndikojë në asnjë mënyrë vlerën e tij në këtë lidhje.

Epo, kjo është ajo, zgjidhja. Thjesht pasi kemi krijuar një rekord të ri, lexojmë vlerën e ndryshores së sistemit @@ IDENTITY dhe kemi vlerën e dëshiruar.

Në përgjithësi, është e vërtetë. Problemi i vetëm është se ndryshorja e sistemit @@ IDENTITY ndryshon vlerën e saj kur krijohet një rekord në ndonjë tabela.

Në praktikë, kjo do të thotë që nëse një insert insert vendoset në një tabelë, në trupin e së cilës jepet një komandë INSERT për të krijuar një rekord në një tabelë tjetër, e cila, nga ana tjetër, ka gjithashtu një fushë me vetinë IDENTITY, atëherë Variabli i sistemit @@ IDENTITY do të marrë vlerën e fushës nga kjo tabelë e dytë.

Me fjalë të tjera, mund të mbështeteni në vlerën e ndryshores së sistemit @@ IDENTITY, por mbani mend se kjo ndryshore nuk është e lidhur me vlerën e një fushe në një tabelë.

Vlera e kthyer nga funksioni SCOPE_IDENTITY ().

U prezantua versioni MS SQL 2000 funksionin e sistemit SCOPE_IDENTITY (). Ky funksion gjithashtu kthen vlerën e fushës me vetinë IDENTITY të rekordit të fundit të krijuar, por të krijuar brenda SCOPE aktuale.

Është mjaft e vështirë të përkthehet në mënyrë adekuate termi SCOPE në Rusisht. Por, përafërsisht, mund të thuash këtë: SCOPE është një procedurë ose funksion. Me fjalë të tjera, SCOPE_IDENTITY () do të kthejë vlerën e fushës me vetinë IDENTITY të rekordit të fundit të krijuar brenda procedurës ku është thirrur ky funksion.

Një nxitës është një SCOPE i ndryshëm (një funksion i ndryshëm), kështu që nuk do të ndikojë në asnjë mënyrë në vlerën e kthimit të SCOPE_IDENTITY ().

Edhe nëse dy përdorues kanë thirrur të njëjtën procedurë në të njëjtën kohë, por secili ka thirrur procedurën në SCOPE e tij. ato. përsëri nuk ka konflikt.

Disavantazhet e këtij funksioni është se ai duhet të thirret brenda SCOPE, ku u krijua rekordi i ri i tabelës me interes për ne. Dhe kjo nuk është gjithmonë e mundur.

Me fjalë të tjera, për të përdorur SCOPE_IDENTITY () në mënyrë korrekte, duhet të monitoroni gjithmonë shtrirjen e SCOPE. Shpesh duke krijuar procedura të veçanta.

Gjetja e një rekordi të ri sipas vlerës së fushave të tjera

Nëse ju kujtohet, problemi kryesor me përcaktimin e vlerës së një fushe me vetinë IDENTITY është se kjo fushë përdoret si çelësi kryesor. ato. është me vlerën e tij që gjendet rekordi i kërkuar.

Megjithatë, shpesh tabelat kanë një fushë ose grup fushash me anë të të cilave një rekord gjithashtu mund të identifikohet në mënyrë unike. Për shembull, nëse vjen në lidhje me drejtorinë, atëherë, sigurisht, drejtoria ka një fushë "Emri". Është gjithashtu e qartë se kjo fushë duhet të jetë unike brenda drejtorisë. Përndryshe, kuptimi i përdorimit të vetë librit të referencës thjesht humbet. Pse futni rekorde me të njëjtën vlerë?

Pse të mos e përdorni këtë "Emër" si çelësin kryesor? Pse ju duhet fare një fushë me pronësinë IDENTITY? Kjo është një temë për një tjetër bisedë. Me pak fjalë, "Titulli" është për përdoruesin (të dhënat e jashtme), dhe IDENTITY është për të siguruar integritetin referencial të bazës së të dhënave (të dhënat e brendshme).

Vlera e fushës me vetinë IDENTITY në rekordin e ri nuk dihet. Por kuptimi i fushës “Titulli” në këtë rekord të ri dihet mirë. Përdoruesi e ka futur vetë! Kjo do të thotë që pas krijimit të një rekord të ri, ju mund ta gjeni këtë rekord të ri sipas vlerës së fushës "Emri" dhe të lexoni vlerën e fushës me vetinë IDENTITY.

Problemi i vetëm është se një fushë e tillë ose grup fushash nuk ekziston gjithmonë për të identifikuar në mënyrë unike një rekord. Nga rruga, kjo është një nga arsyet e futjes së të ashtuquajturave çelësa zëvendësues. Të njëjtat fusha me veçorinë IDENTITY.

Nëse, megjithatë, vendosni të përdorni këtë strategji për të gjetur një rekord të ri, sigurohuni që të vendosni një kufizim unik në fushën "Emri" (ose grupin e fushave që keni zgjedhur). Kjo do të thotë, në mënyrë që të mos ketë dy regjistrime me të njëjtën vlerë në këtë fushë rastësisht.

Si të punoni me fushat me veçorinë IDENTITY në FoxPro

Me përfundimin e pjesës teorike, tani "le të përpiqemi të ngrihemi me gjithë këtë të mirë". ato. le të vendosim se si t'i përdorim të gjitha këto njohuri në FoxPro. Le të sqarojmë edhe një herë problemin që duhet zgjidhur.

Një rekord shtohet në tabelën e serverit MS SQL me një fushë me vetinë IDENTITY. Është e nevojshme të merret vlera e fushës me vetinë IDENTITY në anën e FoxPro menjëherë pas krijimit të një rekord të ri.

FoxPro ka tre opsione themelore për organizimin e punës me serverin MS SQL

  • Duke përdorur pamjen në distancë
  • Duke përdorur përshtatësin e kursorit

Këtu duhet të ndaleni se cila ngjarje në të vërtetë krijon një rekord në serverin MS SQL. Epo, me Pass-Trough, gjithçka është e qartë. Kjo është në fakt një komandë e drejtpërdrejtë për serverin për të krijuar një rekord të ri. Por me pamjen në distancë dhe përshtatësin e kursorit është pak më ndryshe.

Rezultati i punës së Remote View dhe Adapterit të Kursorit është një kursor. ato. disa tavolina të përkohshme të vendosura fizikisht në makinën e klientit. Si parazgjedhje, ky kursor hapet automatikisht në buferimin optimist të rreshtit (3) dhe mund të kalohet vetëm në buferimin optimist të tabelës (5). Është e pamundur të kalosh në modalitetin e buferimit pesimist ose të çaktivizosh fare bufferimin për këtë kursor.

Rrjedhimisht, një rekord i ri fillimisht do të krijohet fizikisht në makinën e klientit pikërisht në këtë kursor. Më saktësisht, në buferin e këtij kursori. Krijimi fizik i një rekordi në serverin MS SQL do të ndodhë vetëm pasi tampon të jetë shpëlarë.

Për bufferimin e vargjeve, buferi mund të shpëlahet automatikisht duke bërë një nga sa vijon:

  • Duke kërcyer (ose duke u përpjekur për të kërcyer) në një rekord tjetër
  • Mbyllja e kursorit
  • Kalimi në modalitetin e buferimit të tabelës
  • Me komandën TableUpdate ()

Për buferimin e tabelës, buferi mund të pastrohet vetëm nga komanda TableUpdate () dhe jo ndryshe.

Asnjë veprim dhe operacion tjetër me pamjen në distancë ose me përshtatësin e kursorit nuk do të krijojë një rekord të ri në serverin MS SQL. Nëse, gjatë ekzekutimit të ndonjë operacioni, doli se u krijua një rekord i ri në serverin MS SQL, kjo do të thotë që kursori ishte në modalitetin e bufferimit të linjës dhe ndodhi një nga ngjarjet që shkaktoi shpëlarjen automatike të tamponit.

Për shembull, kjo mund të ndodhë me komandën Requery () për pamjen në distancë. Por kjo nuk do të thotë se komanda Requery () lan buffer. Aspak. Vetëm një nga kushtet për ekzekutimin e komandës Requery () është mbyllja e kursorit paraekzistues. Por kjo ngjarje do të shkaktojë vetëm shpëlarjen automatike të tamponit nëse kursori është në modalitetin e bufferimit të linjës.

Për të shmangur keqkuptime të tilla, kaloni kursorin në modalitetin e tavolinës me bufer (5). Në këtë rast, gjithmonë mund të kontrolloni procesin e shpëlarjes së tamponit.

Sidoqoftë, duhet të kuptohet se edhe nëse vendosni modalitetin e buferimit të tabelës, ndryshoni disa regjistrime në Remote View ose Adapter Kursor dhe më pas lëshoni komandën TableUpdate (), buferi do të vazhdojë të pastrohet një rekord në të njëjtën kohë. ato. jo një komandë do t'i dërgohet serverit, për shembull, për modifikim, por një grup komandash për modifikimin e secilit rekord veç e veç.

Në lidhje me operacionet e krijimit të një rekordi të ri, nga kjo rrjedh se në të gjitha ngjarjet e përshtatësit të kursorit gjithmonë vetëm një regjistrim futet në të njëjtën kohë.

Përdorimi i drejtpërdrejtë i teknologjisë Pass-Through përmes funksionit SQLEXEC ().

Me këtë metodë pune, programuesi punon drejtpërdrejt me serverin MS SQL. Ai vetë formon të gjitha komandat e dërguara në server, merr rezultatin dhe e përpunon atë vetë. Në këtë rast, nuk është e vështirë të dërgoni një kërkesë shtesë në server për vlerën e funksionit SCOPE_IDENTITY.

LOCAL lcNewValue, lnResut lcNewValue = "(! LANG: Vlera e re" lnResut = SQLExec(m.lnConnectHandle,"INSERT INTO MyTab (Field1) VALUES (?m.lcNewValue)") IF m.lnResut>0 SQLExec(m.lnConnectHandle,"SELECT NewIdent=SCOPE_IDENTITY()","NewIdent") ?NewIdent.NewIdent ELSE LOCAL laError(1) =AERROR(laError) * Анализ массива laError для уточнения причины ошибки ENDIF !}

V ky shembull m.lnConnectHandle është një numër, numri i lidhjes me serverin MS SQL, i cili është konfiguruar më herët. MyTab është një tabelë që ka një fushë me një veçori IDENTITY.

Pas ekzekutimit të pyetjes së dytë në kursorin që rezulton NewIdent në fushën NewIdent të rekordit të parë dhe merrni vlerën e dëshiruar. V sintaksë e dhënë si komanda insert ashtu edhe thirrja e funksionit SCOPE_IDENTITY () ndodhin në të njëjtin SCOPE. Prandaj, marrim vlerën e dëshiruar.

Duke përdorur pamjen në distancë

Remote View është një lloj "shtese" mbi teknologjinë Pass-Through. Në thelb, e njëjta komandë INSERT INTO ekzekutohet kur krijohet një rekord i ri. Megjithatë, problemi është se edhe nëse lexoni numrin e lidhjes në të cilën funksionon Remote View, dhe më pas ekzekutoni një pyetje për të përcaktuar vlerën e kthyer nga SCOPE_IDENTITY (), do të marrim NULL, pasi në këtë rast komanda insert dhe SCOPE_IDENTITY () janë ekzekutuar në SCOPE të ndryshme. Prandaj, ekzistojnë vetëm dy mënyra për të përcaktuar vlerën e një fushe me vetinë IDENTITY.

* Përcaktimi i vlerës së ndryshores së sistemit @@ IDENTITY LOCAL lnConnectHandle lnConnectHandle = CursorGetProp ("ConnectHandle", "MyRemoteView") SQLExec (m.lnConnectHandle, "SELECT [email i mbrojtur]@IDENTITY "," NewIdent ")? NewIdent.NewIdent * Përcaktoni nga vlera e një fushe LOCAL lnConnectHandle, lcNickName lnConnectHandle = CursorGetProp (" ConnectHandle "," MyRemoteView ") lcNickName = MyRemoteView.NickeNeCOMMeCtNeCtLeCtName = MyRemoteView.NickeCOM KU pseudonimi =? LcNickName "," NewIdent ")? NewIdent.TabId

Në të dy shembujt, MyRemoteView është emri i pamjes suaj në distancë. NickName është emri i fushës në pamjen në distancë me vlerën e së cilës kërkohet një rekord i ri dhe TabID është e njëjta fushë me vetinë IDENTITY vlera e së cilës duhet të përcaktohet

Supozohet se krijimi i një rekordi të ri tashmë ka ndodhur. Ose komanda TableUpdate () është dhënë në mënyrë eksplicite, ose "Pamja në distancë" është në modalitetin e vargut të buferit dhe është bërë një përpjekje për të lundruar në një rekord tjetër.

Dhe pse në rastin e dytë, do të duket, më shumë zgjidhje e dukshme kërko pas Kërkesës ()? Diçka si

KËRKONI ("MyRemoteView") SELECT MyRemoteView LOCATE FOR NickName = "Vlera e re"? MyRemoteView.TabID

Ka disa arsye për këtë.

Së pari, Requery () supozon se pyetja është ekzekutuar përsëri. ato. supozohet se buferi i të gjitha regjistrimeve të Remote View është flushed. Por kjo mund të mos jetë kështu. Për shembull, shpëlajeni bufferin një nga një rekord në një lak.

Së dyti, zakonisht Pamja në distancë përmban kushte shtesë përzgjedhja e regjistrimeve, dhe rekordi i krijuar rishtazi mund të mos përfshihet fare në kushtet e përzgjedhjes. ato. pas Kërkesës (), rekordi, megjithëse do të krijohet fizikisht në server, nuk do të shfaqet në vetë pamjen në distancë.

Duke përdorur përshtatësin e kursorit

Objekti i përshtatësit të kursorit u prezantua në FoxPro duke filluar me Visual FoxPro 8. Ai është krijuar për ta bërë më të lehtë punën me të dhëna në distancë kur kryeni disa operacionet standarde... Në veçanti, operacionet e krijimit të një rekord të ri. Nëpërmjet përshtatësit të kursorit, mund të zbatoni të tre opsionet për marrjen e vlerës së një fushe me vetinë IDENTITY në një rekord të ri.

Vlera e kthyer nga ndryshorja e sistemit @@ IDENTITY

Pasi tampon të jetë shpëlarë dhe një rekord i ri të krijohet fizikisht në serverin MS SQL, ngjarja AfterInsert do të aktivizohet në objektin Adapter të Kursorit. Këtu në të ju vetëm duhet të bëni një kërkesë shtesë në server dhe të lexoni vlerën e ndryshores së sistemit @@ IDENTITY

PROCEDURA Pas futjes së LPARAMETrave cFldState, lForce, cInsertCmd, lRezultati IF lRezultat = .T. Futja e && ishte e suksesshme. Ju duhet të merrni vlerën e ID-së LOCAL aktualeArea Area aktuale = SELECT () TRY IF 1 = SQLEXEC (this.DataSource, "SELECT [email i mbrojtur]@IDENTITY "," NewIdent ") REPLACE TabId WITH NewIdent.NewIdent IN (This.Alias) PËRDORIMI NË IDRes ELSE LOCAL laGabim (1) = AERROR (laError) * Analizoni grupin laError për të sqaruar shkakun e gabimit ENDIFY FINALLY Zona aktuale) ENDTRY ENDIF ENDPROC

Unë mendoj se kodi është mjaft i qartë dhe nuk ka nevojë për ndonjë shpjegim. Pas krijimit të suksesshëm të një rekord të ri në server duke përdorur SQLExec (), vlera @@ IDENTITY u përcaktua për të njëjtën lidhje dhe u shkrua në rekordin aktual të kursorit në fushën kryesore.

Në Visual FoxPro 9, një veti iu shtua objektit Adapter i Kursorit FutCmdRefreshCmd... Kjo është një komandë që dërgohet në server vetëm pas futjes me sukses të një rekordi të ri. ato. nuk ka nevojë të bindemi për vetë faktin e krijimit të një rekordi të ri.

Shoqërohet me një tjetër pronë të re InsertCmdRefreshFieldList ju mund të përmirësoni më lehtë nga ndryshorja e sistemit IDENTITY @@. Për ta bërë këtë, ju vetëm duhet të bëni cilësimet e mëposhtme Objekt CursorAdapter

CursorAdapter.InsertCmdRefreshCmd = "SELECT @@ IDENTITY" CursorAdapter.InsertCmdRefreshFieldList = "TabId"

Këtu TabId nuk është emri i fushës me vetinë IDENTITY në tabelën e vetë serverit MS SQL, por emri i fushës së kursorit të marrë në anën e klientit në të cilën shfaqet përmbajtja e fushës me vetinë IDENTITY. Si rregull, këta emra janë të njëjtë, por, në përgjithësi, ato mund të jenë të ndryshme. Mësoni më shumë rreth pronës InsertCmdRefreshFieldList Lexo me poshte. Në seksionin për gjetjen e një rekordi të ri sipas vlerës së fushave të tjera.

Vlera e kthyer nga funksioni SCOPE_IDENTITY ().

Këtu, gjithçka është disi më e ndërlikuar. Çështja është se nuk mund të veproni në të njëjtën mënyrë si në rastin e përcaktimit të ndryshores së sistemit IDENTITY @@. SQLExec () dhe përshtatësi i kursorit funksionojnë në SCOPE të ndryshme. Prandaj, me këtë qasje, SCOPE_IDENTITY () do të kthejë gjithmonë NULL. Për të kapërcyer këtë kontradiktë, përdoren procedura të veçanta.

Së pari, ju duhet të krijoni një procedurë të tillë të ruajtur në vetë serverin MS SQL

KRIJO PROCEDURE Get_ValueInt @ValueIn Int, @ValueOut Int OUTPUT SI SET NO COUNT ON SELECT @ [email i mbrojtur]

Siç mund ta shihni, qëllimi i kësaj procedure është thjesht të caktojë vlerën e një parametri hyrës një parametri dalës. Tani mund ta përdorni këtë procedurë për të përcaktuar vlerën SCOPE_IDENTITY () në përshtatësin e kursorit. Për ta bërë këtë, në rast Para Insert bëhet një zëvendësim i tillë

PROCEDURA Përpara futjes së LPARAMETRAVE cFldState, lForce, cInsertCmd cInsertCmd = cInsertCmd +; "; DEKLARONI @id int" +; "; SELECT @ id = SCOPE_IDENTITY ()" +; "; EXEC Get_ValueInt @id, [email i mbrojtur]"ENDPROC

Vetëm mbani në mend se në këtë zëvendësim MyTab nuk është më emri i tabelës në serverin MS SQL, por emri i kursorit të krijuar nga klienti. Më saktësisht, emri që është regjistruar në vetinë Alias ​​të vetë përshtatësit të kursorit. Prandaj, "TabId" është emri i fushës së kursorit të krijuar nga klienti dhe që përmban vlerën e fushës me vetinë IDENTITY

Në këtë rast, në thelb, formohet një procedurë dinamike e ruajtur. ato. jo vetëm një komandë INSERT, por një sekuencë komandash. Komandat ndahen nga njëra-tjetra me pikëpresje, megjithëse kjo nuk kërkohet. Mjafton të ndani komandat nga njëra-tjetra me një hapësirë ​​të thjeshtë.

Gjetja e një rekordi të ri sipas vlerës së fushave të tjera

Nëse keni Visual FoxPro 8, atëherë gjithçka që duhet të bëni është të përdorni një metodë të ngjashme me metodën e përdorur për të gjetur vlerën e ndryshores së sistemit @@ IDENTITY. ato. në metodën AfterInsert të objektit Adapter i kursorit, ekzekutoni një kërkesë shtesë nëpërmjet SQLExec ()

Duke filluar me Visual FoxPro 9, objekti Adapter i Kursorit ka veçori shtesë për të automatizuar këtë procedurë pa shkruar kod shtesë.

InsertCmdRefreshFieldList- një listë fushash, vlera e të cilave do të përditësohet pas Futjes
InsertCmdRefreshKeyField List- një fushë, ose një grup fushash JO kyçe që identifikojnë gjithashtu në mënyrë unike rekordin, i cili do të përdoret për të kërkuar një rekord të ri

Duhet të theksohet se këto veti nuk specifikojnë emrat e fushave të tabelës së vetë serverit MS SQL, por emrat përkatës të fushave të kursorit të marra në anën e klientit. Për të njëjtin shembull, do të ishte diçka si kjo:

InsertCmdRefreshFieldList = "TabID" InsertCmdRefreshKeyFieldList = "Nofka"

Me fjalë të tjera, bazuar në vlerën e fushës NickName, një rekord do të gjendet në tabelë në serverin MS SQL dhe do të lexohet vlera e fushës TabID, pas së cilës kjo vlerë do të shkruhet në një rekord të ri në anën e klientit.


Në mënyrë më të detajuar, si një diskutim i kësaj teme ashtu edhe shembuj të përdorimit mund të shihni këtu



Vladimir Maximov
Përditësimi i fundit: 01.05.06

Artikujt kryesorë të lidhur