Discussion:
IBDataset und Autoincrement
(zu alt für eine Antwort)
Alfred Gemsa
2012-12-17 07:08:25 UTC
Permalink
Hallo,

in einer Tabelle gibt's ein Feld ID, dass über einen Generator und ein
Before_Insert-Trigger hochgezählt werden soll.

Das IBDataset hat diesbezüglich eine Eigenschaft "GeneratorField", die
auf den Generator, den Feldnamen und "Anwenden bei neuem Datensatz"
gesetzt ist.

Dummerweise zählt ID aber jeweils um Zwei hoch, wenn ich mittels
Dataset.Append einen Record dranhänge.

Was mache ich falsch?

Alfred.
Achim Kalwa
2012-12-17 12:09:05 UTC
Permalink
Hallo,
Post by Alfred Gemsa
in einer Tabelle gibt's ein Feld ID, dass über einen Generator und ein
Before_Insert-Trigger hochgezählt werden soll.
Das IBDataset hat diesbezüglich eine Eigenschaft "GeneratorField", die
auf den Generator, den Feldnamen und "Anwenden bei neuem Datensatz"
gesetzt ist.
Dummerweise zählt ID aber jeweils um Zwei hoch, wenn ich mittels
Dataset.Append einen Record dranhänge.
Was mache ich falsch?
Ich kenne zwar IBDataset nicht im Detail, aber das sieht mir so aus als
würde IBDataset sich selber um die Vergabe einer neuen ID kümmern. Dabei
wird der Generator zum ersten Mal inkrementiert. Dein Trigger macht dann
das gleiche noch einmal.

Zeig' doch mal den Code vom Trigger.
Evtl. kannst Du den so umbauen, dass der nur dann Generator angesprochen
wird, wenn ID noch keinen Wert hat:

create trigger TBI_KUNDE for KUNDE before insert
position 0 as
begin
if (new.ID IS NULL) then new.ID = GEN_ID(G_ID, 1);
end

(G_ID ist der Generator)

HTH
Achim
Alfred Gemsa
2012-12-17 12:32:38 UTC
Permalink
Post by Achim Kalwa
Ich kenne zwar IBDataset nicht im Detail, aber das sieht mir so aus als
würde IBDataset sich selber um die Vergabe einer neuen ID kümmern. Dabei
wird der Generator zum ersten Mal inkrementiert. Dein Trigger macht dann
das gleiche noch einmal.
Zeig' doch mal den Code vom Trigger.
Evtl. kannst Du den so umbauen, dass der nur dann Generator angesprochen
create trigger TBI_KUNDE for KUNDE before insert
position 0 as
begin
if (new.ID IS NULL) then new.ID = GEN_ID(G_ID, 1);
end
IBExpert zeigt mir folgendes:

/******************************************************************************/

/**** Generated by IBExpert 17.12.2012 07:15:05
****/
/******************************************************************************/


SET SQL DIALECT 3;

SET NAMES NONE;

CREATE TABLE NEW_TABLE (
ID INTEGER NOT NULL,
NAME CHAR(10)
);

ALTER TABLE NEW_TABLE ADD CONSTRAINT PK_NEW_TABLE PRIMARY KEY (ID);

CREATE GENERATOR GEN_NEW_TABLE_ID;

SET TERM ^ ;

/* Trigger: NEW_TABLE_BI */
CREATE TRIGGER NEW_TABLE_BI FOR NEW_TABLE
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.ID IS NULL) THEN
NEW.ID = GEN_ID(GEN_NEW_TABLE_ID,1);
END
^

SET TERM ; ^


Das sieht nicht so verkehrt aus.

Alfred.
Achim Kalwa
2012-12-17 19:28:04 UTC
Permalink
Moin,
Post by Alfred Gemsa
CREATE TRIGGER NEW_TABLE_BI FOR NEW_TABLE
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.ID IS NULL) THEN
NEW.ID = GEN_ID(GEN_NEW_TABLE_ID,1);
END
Ja, das sieht gut aus. Und vermutlich funktioniert es prima, wenn Du per
IBExpert oder einem anderen SQL-Tool Daten in die Tabelle schreibst:

insert into NEW_TABLE(NAME) values ('TEST');

Dabei sollte der Trigger ausgelöst werden und das hier fehlenden Feld
"ID" befüllen. Dabei wird Generator immer nur um 1 erhöht.

Jetzt zurück zu IBDataset. Wenn dort nach einer vergleichbaren Aktion
der Generator um 2 erhöht ist, dann bekommt IBDatabase nix davon mit,
dass da im Hintergrund noch ein Trigger aktiv ist, der ebenfalls eine ID
erzeugt.

Also entweder
a)
auf den Trigger verzichten und nie niemals nicht Daten von Hand per SQL
eingeben...

b)
im IBDataset die Generator-Option wieder abschalten; der Trigger kümmert
sich um die Vergabe einer ID.

Vermutlich willst Du aber *nach* dem .Post die ID des neuen Datensatzes
kennen. Dann bleibt Dir nichts anderes übrig, als *vor* dem .Post selber
den Generator abzufragen und die gelieferte ID in das IBDataset zu
schreiben (OnNewRecord).

HTH
Achim
Alfred Gemsa
2012-12-17 20:31:02 UTC
Permalink
Post by Achim Kalwa
Also entweder
a)
auf den Trigger verzichten und nie niemals nicht Daten von Hand per SQL
eingeben...
b)
im IBDataset die Generator-Option wieder abschalten; der Trigger kümmert
sich um die Vergabe einer ID.
b) ist richtig!

Wozu hat das aber IBDataset die Generator-Eigenschaft?
Post by Achim Kalwa
Vermutlich willst Du aber *nach* dem .Post die ID des neuen Datensatzes
kennen. Dann bleibt Dir nichts anderes übrig, als *vor* dem .Post selber
den Generator abzufragen und die gelieferte ID in das IBDataset zu
schreiben (OnNewRecord).
Das verstehe ich nicht: Beim "Append" trage ich Daten nur in die übrigen
Felder ein, das Insert-SQL des IBDatasets lautet (ich habe neben ID nur
noch das Feld NAME):

"insert into TB1 (NAME) values (:NAME)"

Nach dem Post sind dann alle IDs selbständig gefüllt, und ich kann sie
ganz einfach abfragen.

Danke,

Alfred
Martin Behrens
2012-12-18 20:24:58 UTC
Permalink
Post by Alfred Gemsa
Post by Achim Kalwa
Also entweder
a)
auf den Trigger verzichten und nie niemals nicht Daten von Hand per SQL
eingeben...
b)
im IBDataset die Generator-Option wieder abschalten; der Trigger kümmert
sich um die Vergabe einer ID.
b) ist richtig!
Das kommt darauf an, wo man diese Logik platziert.
Post by Alfred Gemsa
Wozu hat das aber IBDataset die Generator-Eigenschaft?
Damit man keinen Trigger dafür braucht.
Post by Alfred Gemsa
Post by Achim Kalwa
Vermutlich willst Du aber *nach* dem .Post die ID des neuen Datensatzes
kennen. Dann bleibt Dir nichts anderes übrig, als *vor* dem .Post selber
den Generator abzufragen und die gelieferte ID in das IBDataset zu
schreiben (OnNewRecord).
Das verstehe ich nicht: Beim "Append" trage ich Daten nur in die übrigen
Felder ein, das Insert-SQL des IBDatasets lautet (ich habe neben ID nur
"insert into TB1 (NAME) values (:NAME)"
Nach dem Post sind dann alle IDs selbständig gefüllt, und ich kann sie
ganz einfach abfragen.
Das einfache Abfragen dürfte dann spätestens beim Multiuserbetrieb zum
Problem werden.
Die ID zu bestimmen kann dann schon ein erhebliches Problem darstellen.

Ich bin der Meinung, dass man sich für die Durchsetzungs solcher Regeln
(ID Vergabe) auf einen Weg festlegen muss: Entweder setzt man es auf
Datenbankebene durch oder auf Applikationsebene durch. Beides hat Vor-
und Nachteile.


Martin

Lesen Sie weiter auf narkive:
Loading...