Einzelnen Beitrag anzeigen

jobo

Registriert seit: 29. Nov 2010
3.072 Beiträge
 
Delphi 2010 Enterprise
 
#14

AW: FireDac den AutoInc value in onBeforePost abfragen. (ist immer -x)

  Alt 3. Sep 2022, 14:43
Ein AutoInc Field zur Befüllung eines PK wird aus Sicht der DB entweder über
  • den Spaltentyp geregelt oder
  • über einen Trigger mit Hilfe eines Generators oder
  • nur über einen Generator.

Anscheinend gibt es in
<=V. 2.5:
nur Generatoren, diese können mit Triggern zur Befüllung kombiniert werden
V. 3:
die Spaltendefinition "by default as identity primary key"
V. 4:
die Spaltendefinition "always as identity primary key"

zu "<=2.5" bzw. überall dort wo ein Trigger im Einsatz ist:
Die Existenz und Nutzung eines Triggers sagt nichts über die zwangsweise Nutzung des Generatorwertes. Trigger sind häufig so geschrieben, dass sie einen mitgegebenen Wert (durch das Insert) verwenden. (siehe unten)

zu 3: "..by default.." verhält sich analog zum häufig so wie oben beschriebenen Triggeraufbau, es setzt nur den Defaultwert mittels einer (internen) Sequenz, dieser bleibt aber überschreibbar. Also gleiche Funktionalität wie zuvor, nur ohne den selbst erstellten Trigger.

zu 4: ".. always .." verwendet immer den internen Sequenzwert, benötigt auch keinen Trigger.

Nach der Befüllung nutzt man die Rückgabe/Abfrage des Generators zur Weiterverwendung dieses Wertes bspw. in FKs. Wird ein Generator verwendet, dann per fragt man den letzten Wert so ab:
Code:
SELECT GEN_ID( GeneratorName, 0 ) FROM RDB$DATABASE;
(oder innerhalb eines anderen SQL Statements)
Seit FB 2.0 kann auch gleich per RETURNING im Insert Statement der Wert zurückgegeben werden.
Das ist der sicherste und bequemste Weg, diesen Wert zu erfahren, weil er unabhängig von der Erzeugung ist.

Das bis jetzt beschriebene Verhalten muss sich alles per SQL in der Kommandozeile nachvollziehen lassen (Es muss natürlich entsprechend in den Tabellen richtig definiert sein).

Die FD Kompos und ihr Verhalten kenne ich nicht. (Was ich hier schreibe, habe ich nicht in Delphi validiert) Sie müssen aber alles oben beschriebene berücksichtigen und können nicht tiefer eingreifen, als es mit bloßem SQL geht. Sie bieten aber "Komfortproperties" zur einfacheren Handhabung.
Wenn man in den Properties einen Generatornamen angeben kann, dann sollte es für das gewünschte Verhalten auch gemacht werden.
Ab FB 3 sollte es nicht nötig sein, einen Generator anzulegen, wenn die Spalte mit "..generated.." definiert wurde. (Mir ist nicht klar, ob die FD Kompos das 'generated' Feature überhaupt berücksichtigen)

Zeitpunkt (Before/After- für DB und Delphi)
Alles was die DB macht (an Werten ändert/ergänzt), kann Delphi (im Prinzip egal welcher Client) nicht wissen, solange das Insert nicht abgeschlossen ist. (Ausnahme, es gibt keine Trigger, keine Generated Spalten und auch keine Defaults, dann ist bei einem simplen Insert aus dem Client auch das Ergebnis bekannt, weil identisch). Eine zeitliche Unterscheidung gibt es dabei nur mittels Trigger. Das wird ja auch beim Insert Trigger "before insert" für "new.IDcolumn" genutzt.

Ein Client kann eigentlich nur 2 Dinge tun:
Entweder er holt selbst einen neuen Generatorwert, bevor das Insert erfolgt und übergibt den Wert an das Insert.
Oder er holt nach dem Insert den aktuellen Generatorwert und stellt ihn innerhalb der Komponente zur Weiterverwendung (Anzeige, ..) zur Verfügung.

Wenn man nach dem Insert einen Wert aus dem Client überschreibt- wie @kostas es darstellt-, sollte der auch gezielt gepostet werden, sonst geschieht das Posten gar nicht oder ungezielt irgendwann implizit, man zerstört zu einem ungewissen Zeitpunkt also den Originalwert. Damit verlässt man die Vorgaben, die DB Seitig festgelegt wurden. Es handelt sich aus DB Perspektive dann um ein Update.

Der von @kostas gepostete Trigger
[code]
CREATE OR ALTER trigger bankdatenschulungen_bi for bankdatenschulungen
active before insert position 0
as
begin
if (new.bankdatenschulungenid is null) then
new.bankdatenschulungenid = gen_id(gen_bankdatenschulungen_id,1);
end
[code]
setzt die ID new.bankdatenschulungenid nur unter der Bedingung, dass das Feld nicht bereits vorbelegt ist(oder auch mitgeliefert wurde- normalerweise durch das Insertstatement). Hat die Spalte also später einen Wert, den man separat angegeben hat, ist es in diesem Fall dem bedingt arbeitenden Trigger zu verdanken und hat erstmal nichts mit Client Komponenten zu tun. Oder der separate Wert kommt durch ein Update, dann ist der Insert Trigger sowieso nicht beteiligt.

Ich habe dazu fiddles angelegt. Diese klären natürlich nicht das Verhalten im Client, verdeutlichen aber hoffentlich so gut es geht das DB Verhalten- welches unumgänglich ist. Bei Interesse bitte Bescheid sagen.
Gruß, Jo
  Mit Zitat antworten Zitat