Einzelnen Beitrag anzeigen

Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.429 Beiträge
 
Delphi 10.4 Sydney
 
#45

AW: SQL Automatisch zugeteilte Id ermitteln.

  Alt 14. Jul 2014, 16:51
Das ist so nicht ganz richtig. Auch der BeforeInsert-Trigger der Datenbank wirkt erst, nachdem der Datensatz per Post an den Server übergeben wurde.
Der Generator – und ich schreibe hier wieder ausschließlich über Firebird, auch wenn ich meine, daß es sich hier um eine generelle Verfahrensweise bei allen modernen DBMS handelt – incrementiert bei BeforeInsert vor dem Posten. In die jeweilige Spalte wird dieser Wert natürlich erst nach dem Posten eingetragen:

This database also maintains a generator named EMP_NO_GEN and a Before Insert trigger named SET_EMP_NO on the EMPLOYEE table, to produce a value for this key whenever a new row is inserted. (Helen Borrie: The Firebird Book)

Wenn die Aktion (insert) nicht abgeschlossen (post) wird (was einem cancel entspricht), setzt der Trigger den einmal erhöhten Generatorwert wieder zurück (rollback):

Work performed by triggers will be rolled back if the transaction that prompted them is rolled back. (Helen Borrie: The Firebird Book)
Der Vorgang "Post" umfasst den Transport des aktuellen Datensatzes vom Client zum Server und das Eintragen dieses Satzes in die Datenbank.
Dazu gehört auch die automatische Ausführung aller Trigger.
Die Besonderheit der Before-Trigger ist, man kann die einzutragenden Werte noch ändern (also z.B. ein leeres ID-Feld füllen).
Tritt bei irgendeinem Schritt ein Fehler auf (z.B. auch in einem After-Trigger) wird der Post-Vorgang abgebrochen.
Dabei werden alle Änderungen an Tabellen rückgängig gemacht, die wärend dieses Posts erfolgt sind.
Aber Generatoren können dabei nicht berücksichtigt werden.
Die im Trigger erzeugte ID ist im Fehlerfall ungültig und wird nicht mehr verwendet.
Das kann man sehr leicht nachprüfen.

Es gibt allerdings Komponenten die den Wert solcher Spalten selbst vorab erzeugen.
Dafür muss dann der für diese Spalte zuständigen Generator angegeben werden.
Die Komponente erzeugt die neue ID über eine interne Abfrage und setzt dabei den Generator hoch:
Code:
select GEN_ID(GEN_ZUSATZKLASSE_ID, 1) from RDB$DATABASE
Dann wirkt aber auch der Trigger nicht mehr, da die Spalte bereits belegt ist.
Verwechselst du da nicht was? Die Id-Spalte des neu anzulegenden Datensatzes wird erst nach dem Post belegt. Würden die DB-Komponenten den Generatorwert von sich aus hochsetzen, würde das bedeuten, daß der Generatorwert immer um 2 erhöht wird, wenn BeforeInsert oder AfterInsert in der DB gesetzt sind, denn der Trigger wird ja auch ohne entsprechende DB-Komponenten im Client allein schon durch den Insert-Befehl ausgelöst, z.B. wenn ich ein SQL-Script mit Insert-Befehlen laufen lasse.
Die vom IB-Expert automatisch erzeugten Trigger prüfen immer ob das Feld noch den Null-Zustand hat, bevor diese eine neue ID erzeugen.
Die Daten des einzufügenden Datensatzes können auch nur im BeforeTrigger verändert werden.

Es ist dagegen fahrlässig, den Generator nur abzufragen ohne den Generatorwert hochzusetzen und sich darauf zu verlassen, dass der Trigger diese ID beim nächsten Post vergibt. Generatoren zählen für alle Transaktion und Datenbankverbindungen. Bis zum eigenen Post kann sich der Generatorwert schon wieder geändert haben und der Trigger vergibt eine andere ID.
Richtig! Für Single-User-Anwendungen spielt das jedoch keine Rolle, bei Multi-User-Anwendungen dagegen schon: Hier sollte man einfach die Id, die nach dem Posten vergeben wurde, aus der jeweiligen Id-Spalte der gerade bearbeiteten Tabelle auslesen. Sollte es irgend eine Spalte in der jeweiligen Systemtabelle geben, die diese LAST_INSERT_IDs protokolliert, besteht dasselbe Problem in einer Multi-User-Umgebung: die letzte eingefügte Id muß nicht zwangsläufig diejenige sein, die der Client eigentlich abrufen möchte – es sei denn, man verwaltet das selbst und hinterlegt in einer weiteren Spalte die entsprechende User-Id.
Hier beist sich die Katze in den Schwanz.
Dazu muss das jeweilige DB-System aber in der Lage sein im Laufe des Post-Vorgangs den Datensatz auf dem Client zu aktualisieren.
Und da gab oder gibt es bei einigen Systemen Schwierigkeiten.
  Mit Zitat antworten Zitat