Entwickler-Ecke

Datenbanken - Mehrfaches Append hintereinander und falsche ID in DB


NOS - Di 09.04.19 21:02
Titel: Mehrfaches Append hintereinander und falsche ID in DB
Hallo zusammen,

ich möchte auf Knopfdruck Daten aus Formularen in eine Firbird DB schreiben. Die Daten sind getrennt zwischen Auftragsdaten und Produktdaten.
Wenn ich nun zunächst die Hauptdaten der DB in die Auftragsdaten Tabelle schreibe, möchte ich mir im Anschluss an das POST die erzeugte ItemID auslesen und diese für jedes Produkt in die Produktdatentabelle schreiben. Allerdings ist die ItemID immer 1, obwohl ich einen Generator etc. erzeugt habe. Der ItemID Wert ist für den ersten Datensatz 1, was also stimmt und der Generator funktioniert somit. Nur wenn ich die Routine 2 mal hintereinander aufrufe funktioniert es nicht. Was mache ich falsch?


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
            ItemDBGrid.DataSource.DataSet.Append;
            // check if we are in insert mode
            if ItemDBGrid.DataSource.DataSet.State = dsInsert then
            begin
             ItemDBGrid.DataSource.DataSet.FieldValues['ITEMTYPE'] := Integer(cbItemType.ItemIndex);
             ItemDBGrid.DataSource.DataSet.FieldValues['ITEMSUBJECT'] := edItemSubject.Text;
             ItemDBGrid.DataSource.DataSet.FieldValues['ITEMCUSTOMERADDRLINE1'] := edRecipientLine1.Text;
             ItemDBGrid.DataSource.DataSet.FieldValues['ITEMCUSTOMERADDRLINE2'] := edRecipientLine2.Text;
             ItemDBGrid.DataSource.DataSet.FieldValues['ITEMCUSTOMERADDRLINE3'] := edRecipientLine3.Text;
             ItemDBGrid.DataSource.DataSet.FieldValues['ITEMCUSTOMERADDRLINE4'] := edRecipientLine4.Text;
             ItemDBGrid.DataSource.DataSet.FieldValues['ITEMCUSTOMERADDRLINE5'] := edRecipientLine5.Text;
             ItemDBGrid.DataSource.DataSet.FieldValues['ITEMCUSTOMERADDRLINE6'] := edRecipientLine6.Text;
             ItemDBGrid.DataSource.DataSet.FieldValues['ITEMNUMBER'] := edItemNumber.Text;
             ItemDBGrid.DataSource.DataSet.FieldValues['ITEMDATE'] := edItemDate.Date;
             ItemDBGrid.DataSource.DataSet.FieldValues['ITEMDESCRIPTION'] := memoItemDescriiption.Text;
             ItemDBGrid.DataSource.DataSet.FieldValues['OVERALLNETTO'] := edOverallNetto.FloatValue;
             ItemDBGrid.DataSource.DataSet.FieldValues['OVERALLINCLUDEDTAX'] := edOverallIncludedTax.FloatValue;
             ItemDBGrid.DataSource.DataSet.FieldValues['OVERALLBRUTTO'] := edOverallBrutto.FloatValue;
             ItemDBGrid.DataSource.DataSet.FieldValues['OVERALLTAX'] := edItemTaxRate.FloatValue;
             ItemDBGrid.DataSource.DataSet.Post;
            end
            else
            begin
             ItemDBGrid.DataSource.DataSet.Cancel;
            end;
            ItemDBGrid.DataSource.DataSet.Refresh;
            // add product data to the db
            // get itemid
            ItemId := ItemDBGrid.DataSource.DataSet.FieldValues['ITEMID'];


Moderiert von user profile iconTh69: Topic aus Datenbanken (inkl. ADO.NET) verschoben am Mi 10.04.2019 um 08:24


Ralf Jansen - Di 09.04.19 21:24

Das sieht eher weniger nach .Net Code aus. Eher nach klassischem Delphi.

Warum sollte nach einem Post Richtung Datenbank plötzlich der Generator Value in einem Wert des DataSets stecken?
Sollte man nicht den Generator Wert vor dem Insert holen in seinen Datensatz schreiben und dann posten?

Wenn es bei dir anders läuft solltest du erklären warum bzw. für die Frage das richtige Subforum wählen wenn das was Delphi spezifisches ist.


NOS - Di 09.04.19 21:44

Ja ... sorry ... es geht um Delphi ... kann ich den Post verschieben oder soll ich dort neu posten?

Ich arbeite sonst nicht mit einem DBGrid und daher ging ich davon aus dass der Post nach dem Append den Record in die DB schreibt, das Refresh diesen im Dataset aktualisiert und ich daraus dann den ItemID sprich Generatorwert auslesen kann.

Wenn ich das händisch mache, wann wird denn der Generatorwert erhöht, wenn nicht beim Post?

P.S. Danke fürs Verschieben ins richtige Subforum :-)


Th69 - Sa 13.04.19 12:06

So wie Ralf geschrieben hat, mußt du selber den ID-Wert aus dem Generator auslesen und setzen:

Delphi-Quelltext
1:
2:
newId := ...; // read from generator
ItemDBGrid.DataSource.DataSet.FieldValues['ITEMID'] := newID;

s. z.B. Databases - Firebird Generators [http://mc-computing.com/databases/Firebird/Generators.html]

Alternativ einen Trigger dafür erzeugen: How to create an autoincrement column? [http://www.firebirdfaq.org/faq29/]

PS: Die einzelnen ItemDBGrid.DataSource.DataSet-Zielen sehen 'ugly' aus (besser z.B. with oder Variable dafür anlegen und benutzen).


NOS - Sa 13.04.19 12:12

Oh ... sorry ... dann kam das falsch rüber ... es ist ein Generator mit trigger in der DB ... drum kam ich darauf dass ich nach dem Post auch die ItemID auslesen kann.

Hier mal der Code aus dem Erzeugen der DB:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
     // create empty offers table
     sqlexec := 'CREATE TABLE ItemTable(ITEMID BIGINT, ' +                               // id
                                       'ITEMTYPE BIGINT, ' +                             // item typ (Rechnung,Angebot,Kostenvoranschlag,Bestellung)
                                       'ITEMCUSTOMER VARCHAR(1000), ' +                  // kunde als text für die listen
                                       'ITEMSUBJECT VARCHAR(1000), ' +                   // betreff text
                                       'ITEMCUSTOMERADDRLINE1 VARCHAR(1000), ' +         // adresszeile 1
                                       'ITEMCUSTOMERADDRLINE2 VARCHAR(1000), ' +         // adresszeile 2
                                       'ITEMCUSTOMERADDRLINE3 VARCHAR(1000), ' +         // adresszeile 3
                                       'ITEMCUSTOMERADDRLINE4 VARCHAR(1000), ' +         // adresszeile 4
                                       'ITEMCUSTOMERADDRLINE5 VARCHAR(1000), ' +         // adresszeile 5
                                       'ITEMCUSTOMERADDRLINE6 VARCHAR(1000), ' +         // adresszeile 6
                                       'ITEMNUMBER VARCHAR(1000), ' +                    // id-nummer (re-nr,an-nr etc.)
                                       'ITEMDATE TIMESTAMP,' +                           // datum
                                       'ITEMDESCRIPTION BLOB SUB_TYPE TEXT, ' +          // beschreibung
                                       // sales and price
                                       'OVERALLNETTO FLOAT, ' +                          // nettopreis
                                       'OVERALLINCLUDEDTAX FLOAT, ' +                    // enthaltene steuer
                                       'OVERALLBRUTTO FLOAT, ' +                         // bruttopreis
                                       // tax
                                       'OVERALLTAX FLOAT ' +                             // steuersatz
                                       ');';
     ExecSQL(sqlexec);
     // create index on ID
     sqlexec := 'CREATE UNIQUE INDEX IDX_ID ON ItemTable(ITEMID);';
     ExecSQL(sqlexec);
     // create autoincrement OfferID
     sqlexec := 'CREATE GENERATOR genID;';
     ExecSQL(sqlexec);
     sqlexec := 'SET GENERATOR genID TO 0;';
     ExecSQL(sqlexec);
     sqlexec := 'CREATE TRIGGER trigID FOR ItemTable ACTIVE BEFORE INSERT POSITION 0 AS BEGIN IF (NEW.ITEMID IS NULL) THEN NEW.ITEMID = GEN_ID(genID, 1); END;';
     ExecSQL(sqlexec);


Kann es sein dass das DataSet oder das DBGrid nicht auf den neuen Record zeigt nach dem Append und ich deshalb immer den falschen Wert erhalte?


Th69 - Sa 13.04.19 14:00

Dann debugge es doch mal und schau dir die anderen FieldValues an (evtl. auch mal die RecNo überprüfen).

Laut TDataSet.Refresh [http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/DB_TDataSet_Refresh.html] wird der Cursor bei einem unidirektionalen DataSet wieder auf den ersten Eintrag gesetzt (das kannst du mittels IsUniDirectional überprüfen).


NOS - Sa 13.04.19 18:06

Also unidirektional ist das DataSet nicht ...

wenn ich mit einer leeren DB anfange ist die RecNo nach dem ersten Post auf 1 und der Datensatz ist ok ...

nach dem 2ten Post ist die RecNo auf 2 aber die Values sind die vom ersten Record ...

TDataSet.Last bringt leider auch nichts ...

Was mache ich grundlegend falsch?


icho2099 - So 14.04.19 09:03

http://www.firebirdfaq.org/faq243/


NOS - Mo 15.04.19 13:04

@icho2099

So war mein Grundgedanke zur Lösung ... geht es denn generell nicht mit Append, Post? Kann ich mir gar nicht vorstellen.