CRecordset und Autoincrementfeld



  • Hallo,

    ich erstelle Datensätze in einem MS SQL-Server. Der Zugriff erfolgt über ODBC mittels CRecordset-Klasse. Diese Datensätze enthalten eine ID-Spalte, die durch die Datenbank automatisch hochgezählt wird. Jetzt möchte ich kurz nach dem Anlegen des Datensatzes ermitteln, welche ID die Datenbank vergeben hat. Das Problem ist, dass dies das einzige Feld ist, was eineindeutig ist und nur einmal mit einem definierten Wert vorkommt. Diesen Wert benötige ich, um später den Datensatz zu ändern. Leider fehlt mir die Idee wie ich das machen könnte. Nach einem Update oder Requery enthalten ja die Datenaustauschvariablen immer die Werte des ersten Datensatzes. Nach dem letzten zu suchen ist auch keine Option, da das Programm mehrfach ausgeführt wird und die anderen Instanzen in der gleichen Zeit weitere Datensätze anlegen können. Hat jemand eine Idee?





  • Hallo Bushmaster,

    danke für die Info. Interessanter Ansatz. Mein Problem ist nur, dass auf dem gleichen Rechner theoretisch mehrere Instanzen des Programms laufen können und hier ist die Frage, was dann unter einer Sitzung verstanden wird. Ist auch schwierig zu testen, da diese Grenzfälle sehr sehr selten auftauchen.
    Außerdem greife ich via CRecordset auf die Datenbank zu. Mit SQL wird es da etwas holprig.


  • Mod

    Es geht hier um Deine Verbindung. Jede Verbindung ist hier eindeutig
    und liefert separate werte.



  • Genau. Wobei SCOPE_IDENTITY sogar ausreichend schlau ist sich nicht von Triggern verwirren zu lassen. Steht aber auch alles auf der von @Bushmaster verlinkten Seite.



  • @AndyDD sagte in CRecordset und Autoincrementfeld:

    Außerdem greife ich via CRecordset auf die Datenbank zu. Mit SQL wird es da etwas holprig.

    Das ist ... doof. Es sollte aber trotzdem funktionieren wenn du direkt danach auf der selben Connection ein SELECT SCOPE_IDENTITY() absetzt.
    Problem darf es eigentlich nur geben, wenn du das selbe Connection-Objekt/-Handle aus mehreren Threads gleichzeitig verwendest.

    Nur dass das Programm mehrfach gleichzeitig ausgeführt wird ist egal. Selbst mehrere Threads im selben Prozess sind egal so lange diese alle ihr eigenes Connection-Objekt/-Handle haben.



  • @AndyDD sagte in CRecordset und Autoincrementfeld:

    Ist auch schwierig zu testen, da diese Grenzfälle sehr sehr selten auftauchen.

    Lässt sich eigentlich recht einfach testen, wenn du zwischen dem Einfügen und dem darauffolgenden SELECT SCOPE_IDENTITY() ein ausreichend langes Sleep einfügst.
    (Theoretisch ginge auch eine Message-Box, aber dabei besteht die Gefahr dass Timer oder andere Message-Handler deiner Anwendung vom Message-Loop der Message-Box aufgerufen werden. Und wenn in so einem Handler dann auch SQL ausgeführt wird, dann könnte dir das den Wert den SELECT SCOPE_IDENTITY() zurückliefert ändern, und dein Test würde ein Problem feststellen das in Wirklichkeit ohne das Hilfskonstrukt zum Testen gar nicht auftreten kann.)


  • Mod

    Ein ODBC Handle aus mehreren Threads ist rein grundsätzlich abhängig vom ODBC Treiber.
    Deshalb empfiehlt es sich so etwas NICHT zu machen.

    Der ODBC Treiber des SQL Server kann das. Dennoch würde ich es nicht machen.
    Ich würde immer je Thread eine Connection aufbauen. Dann ist man auch mit SCOPE_IDENTITY auf der richtigen/sicheren Seite.

    Mehrere Connections aus einer Anwendung sind dahingehend vollkommen OK.

    Was ist mit einem Dynaset? Ich meine dann wird doch auch eine Id Feld aktualsiert....



  • @hustbaer: Erst mal vielen Dank für Deinen Post. Das mit dem Sleep bezieht sich aber nur auf die lokale Maschine. Ich muss aber auch den "zeitgleichen" Einsatz mehrerer Rechner absichern. Der Hintergrund des Projektes ist ein Benutzerverwaltungssystem für Software, die ich selbst geschrieben habe. Ich muss für ein Audit-Trail sämtliche Logins und Logouts in die Datenbank schreiben. Dafür war der Plan, dass ich beim Anmelden einen Datensatz anlege und mir den Wert des Autoincrement-Felds merke. Beim Logout wollte ich diesen Datensatz mittels Update umd die Logoutzeit ergänzen. Nun ist es aber so, dass ein Programm in mehreren Instanzen auf einem Rechner bzw. auch mit dem gleichen User auf mehreren Rechnern laufen kann. Damit können theoretisch "zeitgleich" mehrere Datensätze entstehen, die sich weder im User noch in der Zeit unterscheiden. Damit wäre nur die automatisch erstellte ID ein Unterscheidungsmerkmal. Wenn ich jetzt aber nur ein CRecordset mit den Feldern ID, User, Logintime, Logouttime habe wie kann ich darüber dann die SQL-Befehle übermitteln bzw. deren Ergebnisse holen. Das sind ja dann keine Datensätze sondern einzelne Werte. Das das über das Managementstudio geht weiß ich. Das ist alles etwas Neuland für mich und daher frage ich hier, da mir auch hier bisher immer gut geholfen wurde.


  • Mod

    @Martin-Richter sagte in CRecordset und Autoincrementfeld:

    SCOPE_IDENTITY

    ist alles was Du brauchst...
    Es wurde schon alles gesagt!



  • Moin,
    also ich kenn das so, das direkt nach dem Recordset.Add der Autowert abgefragt werden kann. Der ist dann schon gesetzt. Dann die Datenfelder füllen und dann erst den Update Aufruf ausführen.


Log in to reply