10. januar 2007 - 13:37Der er
10 kommentarer og 1 løsning
Problem med select @@identity
Jeg har et lille problem, som jeg har fundet et workaround på, men vil lige høre om nogen kender til det specifikke problem.
Jeg bruger en MS-SQL server.
Jeg har 2 tabeller som jeg indsætter data i og trækker ID'et ud.
oConn.execute("insert into aaTest(test) values('hgh')") set oRs = oConn.execute("select @@identity") Response.write oRs(0) &"**<br>"
oConn.execute("insert into bbTest(test) values('hgh')") set oRs = oConn.execute("select @@identity") Response.write oRs(0) &"**<br>"
Problemet er at det giver mig resultatet: 31** **
Altså får jeg ikke ID'et fra bbTest ud.
Jeg prøvede så at sætte oRs til nothing: oConn.execute("insert into aaTest(test) values('hgh')") set oRs = nothing set oRs = oConn.execute("select @@identity") Response.write oRs(0) &"**<br>"
oConn.execute("insert into bbTest(test) values('hgh')") set oRs = nothing set oRs = oConn.execute("select @@identity") Response.write oRs(0) &"**<br>"
Det giver mig resultatet: 32** 32**
Altså får jeg det første ID ud med begge "select @@identity". Rent tilfældig mens jeg roede med problemet ko jeg til at sætte nothing før indsættelsen: set oRs = nothing oConn.execute("insert into aaTest(test) values('hgh')") set oRs = oConn.execute("select @@identity") Response.write oRs(0) &"**<br>"
set oRs = nothing oConn.execute("insert into bbTest(test) values('hgh')") set oRs = oConn.execute("select @@identity") Response.write oRs(0) &"**<br>"
Det gav mig resultatet: 33** 29**
Hvilket er det rigtige. Er der nogen der kender til denne problematik, og en bedre løsning på problemet??
Man kan jo nemt komme til at glemme at sætte "set oRs = nothing" foran indsættelsen.
Jeg ved ikke om det virker, men prøv at kalde oRs.Close efter du har hentet det nye id ud af oRs.
Jeg tror det er fordi oRs holder fast i forbindelsen når det er åben og at du derfor får det samme id returneret når du kalder execute (noget med at der kun kan være en aktiv cursor på en forbindelse ad gangen).
Altså skulle jeg mene at dette fungerede:
oConn.execute("insert into aaTest(test) values('hgh')") set oRs = oConn.execute("select @@identity") Response.write oRs(0) &"**<br>" oRs.Close
oConn.execute("insert into bbTest(test) values('hgh')") set oRs = oConn.execute("select @@identity") Response.write oRs(0) &"**<br>" oRs.Close
Det er i øvrigt altid en god idé at lukke og slukke efter sig, når man arbejder med databaser, dvs. både kalde close på recordsettet og forbindelsen, samt sætte objektreferencerne til nothing, så du er sikker på at de bliver frigivet med det samme (det har noget med låsning af resurser at gøre og hvor lang tid du gør det).
du skal bruge SCOPE_IDENTITY() istedet for @identity. @identity returnerer indsat ID globalt for DB så at sige, mens scope_identity returnerer for aktuel session / insert
slash >> det synes jeg da ikke giver mening, da fennec's eksempel så burde returnere det sidste id databasen har genereret og det er jo ikke tilfældet - tvært imod.
fennec >> Ja, og det synes jeg bare underbygger min teori om at sålænge recordsettet er åben, holder den fast i nogle resurser i databasen (via sin cursor iflg. min opfattelse) og du får derfor ikke den nye id tilbage.
Jeg her personligt gjort det til en vane at lukke mine recordsets hurtigst muligt efter jeg er færdig med dem, så slipper jeg for at bøvle med problemer af denne slags. Der er naturligvis situationer hvor jeg er nød til at håndtere et behov for at loope og måske opdatere databasen i dette loop, men det prøver jeg at holde på et minimum, da det er kilde til denne slags problemstillinger...
oConn.execute("insert into aaTest(test) values('hgh')") set oRs = oConn.execute("select SCOPE_IDENTITY() from aaTest") Response.write oRs(0) &"**<br>"
oConn.execute("insert into bbTest(test) values('hgh')") set oRs = oConn.execute("select SCOPE_IDENTITY() from bbTest") Response.write oRs(0) &"**<br>"
Har det samme problem som @@identity. Den returnere kun det første ID: 50** **
Desuden har vi ingen Triggers på tabellerne så @@identity er ok at bruge. Vi kører også noget multidatabase så kunderne selv kan vælge at gøre Access eller MS-SQL (senere også MySQL). Det er derfor vigtitg at sql sætningerne er crossDB, og mig bekendt virker scope ikke i Access (har dog ikke afprøvet det)
Softspot >> Jeg er enig, synes bare det er en mærkelig situation.
oConn.execute("insert into bbTest(test) values('hgh')") oRs.close set oRs = oConn.execute("select @@identity from bbTest")
og oRs.close oConn.execute("insert into bbTest(test) values('hgh')") set oRs = oConn.execute("select @@identity from bbTest")
Burde ikke have forskellig resultater, hvad de dog har. Men point må gå til dig.
Nej, det er ikke altid at MickeySofts implementeringer giver mening på overfladen, men det er jo det der gør det så interessant at være udvikler - hvad har de mon fundet på af kringelkroge denne gang ;D
Anyway! Seriøst, så synes jeg MS' arkitekturer er rimelig konsistente og jeg bøjer mig i støvet for deres evne til at få tingene skruet nogenlunde fornuftigt og forståeligt sammen - det gælder dels arkitekturer men også deres evne til at dokumentere på en konsistent måde.
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.