Identity

Adatbázis és adatelérési réteg tervezésekor gyakran futunk bele abba a problémába, hogy egy táblába beszúrt rekord valamely automatikusan előálló mezőjét a rekord beszúrása után vissza kellene adnunk a tárolt eljárást hívó felsőbb szintű kódnak. Tipikusan egy rekord beszúrása után kellene tudnunk az új rekord azonosítóját.

Ha az azonosító egy int típusú oszlop IDENTITY default értékkel, akkor nincs nagy probléma, csak ki kell bogarászni, hogy a @@IDENTITY, SCOPE_IDENTITY() és IDENT_CURRENT függvények közül melyik lekérdezésével kaphatjuk vissza a beszúrt azonosítót.

Ha az ID oszlopunk uniqueidentifier, akkor azért vagyunk könnyű helyzetben, mert már az adatbázis hívás előtt generálhatunk egy GUID-ot, hiszen annak mindegy, hogy ki hozza létre, ígyis-úgyis egyedi lesz.

Ámde mi van akkor, ha uniqueidentifiert használunk, de NewSequentialID() kezdőértékkel? Ezt nem fogjuk tudni C#-ban generálni, ezt csak az adatbázis fogja tudni, ráadásul az is csak DEFAULT constraintben (vagy aki hajlandó meghívni az UuidCreateSequential API függvényt, amit az SQL is burkol). Nincs más hátra, vissza kell kérdezni a beszúrt sor adatait.

SQL Server 2005-től kezdve az OUTPUT clause segítségével talán ez egy kicsit egyszerűbb. Íme egy példa tábla két automatikusan kitöltött mezővel:

    CREATE TABLE Nevek (
      ID uniqueidentifier DEFAULT( NewSequentialID() ),
      Nev nvarchar( 100 ),
      Datum datetime DEFAULT( GetDate() ),
      Nem char( 1 ) )
    GO

Töltsük fel érdekes adatokkal:

    INSERT INTO Nevek ( Nev, Nem ) VALUES ( 'Ágnes', 'N' )
    INSERT INTO Nevek ( Nev, Nem ) VALUES ( 'András', 'F' )
    INSERT INTO Nevek ( Nev, Nem ) VALUES ( 'Zoltán', 'F' )
    INSERT INTO Nevek ( Nev, Nem ) VALUES ( 'Gábor', 'F' )
    INSERT INTO Nevek ( Nev, Nem ) VALUES ( 'Bogi', 'N' )
    GO

A táblába beszúrhatunk egy rekordot pusztán az alapértékekkel:

    INSERT INTO Nevek DEFAULT VALUES

Ha arra is kíváncsiak vagyunk, hogy mi került a táblába, tegyük a közepére az OUTPUT kulcsszót és használjuk az INSERTED táblát, mintha csak triggerben lennénk:

    INSERT INTO Nevek OUTPUT INSERTED.* DEFAULT VALUES

Persze lehetünk ennél specifikusabbak is, ha nincs szükségünk minden oszlopra:

    INSERT INTO Nevek ( Nev, Nem ) OUTPUT INSERTED.ID, INSERTED.Nev VALUES ( 'Róbert', 'F' ) 

 Mi van akkor, ha a beszúrt azonosító értékét később szeretnénk használni? Nosza töltsük át egy változóba, amihez sajnos kell egy tábla típusú változó is:

    DECLARE @New TABLE( ID uniqueidentifier, Datum datetime )
    INSERT INTO Nevek ( Nev ) OUTPUT INSERTED.ID, INSERTED.Datum INTO @New VALUES ( 'Hassan' ) 
    SELECT ID FROM @New

Sőt, ez nem csak INSERTtel, hanem UPDATE és DELETE utasításokkal is működik. Szeretnénk tudni, hogy egy UPDATE hívás mely rekordokon dolgozott? Már mindent tudunk, csak össze kell rakni:

    UPDATE Nevek
    SET Nem = 'F'
    OUTPUT INSERTED.ID, INSERTED.Nev
    WHERE Nem IS NULL

Természetesen nem csak INSERTED, hanem DELETED tábla is létezik, annak kipróbálása viszont már házi feladat!

 

Technorati tags:
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s