Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   FireDac CopyDataSet kopiert nicht den PK (https://www.delphipraxis.net/186107-firedac-copydataset-kopiert-nicht-den-pk.html)

Kostas 4. Aug 2015 10:48

Datenbank: Firebird • Version: 2.5 • Zugriff über: FireDac

FireDac CopyDataSet kopiert nicht den PK
 
Liste der Anhänge anzeigen (Anzahl: 4)
Hallo Zusammen,

Delphi XE8, FB2.5

CopyDataSet sollten eigentlich die Komplette Datenmänge kopieren.

Delphi-Quellcode:
FDQuery4.CopyDataSet(FDQuery3, [coRestart, coAppend, coEdit]);
Ich habe dafür auch eine Testanwendung erstellt.
Zum testen habe ich eine DB mit vier gleiche Tabellen angelegt.
Alle vier Querys mit dem gleichen Inhalt
Code:
SELECT * FROM KONTAKTE
natürlich jeweils die andere Tabelle.

Beim ausführen von CopyDataSet werden alle Felder kopiert ausser das PK Field.
Genauer gesagt, im Grid wird sogar der PK richtig angezeigt, in der DB jedoch
wird der PK nicht übertragen und somit feuert der Trigger der den nächsten Generatorwert holt.

Ich habe übrigens auch alle andere CopyDataSetOptions ausprobiert, immer das gleiche Verhalten.
Hat jemand eine Idee?

Gruß Kostas

mkinzler 4. Aug 2015 10:58

AW: FireDac CopyDataSet kopiert nicht den PK
 
Wie sieht der Trigger aus? Wirkt der Generator wirklich nur bei leeren Feldern?

Kostas 4. Aug 2015 11:00

AW: FireDac CopyDataSet kopiert nicht den PK
 
Zitat:

Zitat von mkinzler (Beitrag 1310886)
Wie sieht der Trigger aus? Wirkt der Generator wirklich nur bei leeren Feldern?

ja, eigentlich schon.
Delphi-Quellcode:
CREATE OR ALTER trigger kontakte_bi for kontakte
active before insert position 0
as
begin
  if (new.kontaktid is null) then
    new.kontaktid = gen_id(gen_kontakte_id,1);
end

Uwe Raabe 4. Aug 2015 11:42

AW: FireDac CopyDataSet kopiert nicht den PK
 
In deinem Projekt fehlen die Query-Komponenten.

Uwe Raabe 4. Aug 2015 11:52

AW: FireDac CopyDataSet kopiert nicht den PK
 
CopyDataSet setzt bei einem AutoInc-Feld nur dann das IdentityInsert auf true, wenn coStructure mit übergeben wird. Andernfalls musst du das vor dem CopyDataSet selber machen, sonst hält FireDac den Wert für einen lokal erzeugten und lässt die DB den selbst generieren.

Kostas 4. Aug 2015 11:56

AW: FireDac CopyDataSet kopiert nicht den PK
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Uwe, in der Form sind alle vier Querys enthalten. Was könntest du meinen?

Auch coStructure hab ich versucht leider ohne Erfolg.
Delphi-Quellcode:
FDQuery2.CopyDataSet(FDQuery1, [coStructure, coRestart, coAppend, coEdit]);
Gruß Kostas

[Edit]
oh, muss ich revidieren. coStructure scheint zu funktionieren wenn der PK ein Integer ist.
Bei BigInt funktioniert es nicht. Ich habe es vorhin immer nur mit BigInt ausprobiert.

Uwe Raabe 4. Aug 2015 12:04

AW: FireDac CopyDataSet kopiert nicht den PK
 
Zitat:

Zitat von Kostas (Beitrag 1310904)
in der Form sind alle vier Querys enthalten.

In dem Download aber nicht.

Kostas 4. Aug 2015 12:11

AW: FireDac CopyDataSet kopiert nicht den PK
 
Liste der Anhänge anzeigen (Anzahl: 1)
Sorry Uwe,
ich habe das Zip mit allen Files angehängt.

[Edit] in dem aktuellen Projekt benötige ich leider BigInt.
Die PKs auf Integer setzt ist nicht möglich.
Eine Alternative ist natürlich dynamisch das SQL für UPDATE OR INSERT INTO
zu generieren und auf CopyDataSet zu verzichten.

Uwe Raabe 4. Aug 2015 14:08

AW: FireDac CopyDataSet kopiert nicht den PK
 
So sollte es sowohl mit Integer als auch BigInt gehen (auch ohne coStructure):

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  fld: TField;
begin
  fld := FDQuery2.FieldByName('KONTAKTID');
  PrepareAutoIncField(fld);
  FDQuery2.CopyDataSet(FDQuery1, [coRestart, coAppend, coEdit]);
  RestoreAutoIncField(fld);
  FDQuery2.refresh;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  fld: TField;
begin
  fld := FDQuery4.FieldByName('KONTAKTID');
  PrepareAutoIncField(fld);
  FDQuery4.CopyDataSet(FDQuery3, [coRestart, coAppend, coEdit]);
  RestoreAutoIncField(fld);
  FDQuery4.refresh;
end;

procedure TForm1.PrepareAutoIncField(AField: TField);
begin
  if AField is TFDAutoIncField then begin
    (AField as TFDAutoIncField).IdentityInsert := true;
  end
  else begin
    AField.AutoGenerateValue := TAutoRefreshFlag.arNone;
    AField.ProviderFlags := [pfInUpdate, pfInWhere, pfInKey];
  end;
end;

procedure TForm1.RestoreAutoIncField(AField: TField);
begin
  if AField is TFDAutoIncField then begin
    (AField as TFDAutoIncField).IdentityInsert := false;
  end
  else begin
    AField.AutoGenerateValue := TAutoRefreshFlag.arAutoInc;
    AField.ProviderFlags := [pfInWhere, pfInKey];
  end;
end;

Kostas 4. Aug 2015 15:00

AW: FireDac CopyDataSet kopiert nicht den PK
 
Tausend Dank Uwe,

so funktioniert es.

Ich habe in dem Projekt mehrere Stellen in denen ich CopyDataSet
nutze. Es ist bis jetzt nicht aufgefallen. Würdest du das als Bug
bezeichnen? Oder warum gibt es keine Option dieses Verhalten zu steuern? Zumindest habe ich jetzt verstanden dass das zusammenhängt
mit den AutoInc Feldern.

Gruß Kostas

Uwe Raabe 4. Aug 2015 15:07

AW: FireDac CopyDataSet kopiert nicht den PK
 
Zitat:

Zitat von Kostas (Beitrag 1310967)
Würdest du das als Bug
bezeichnen?

Formell ist es kein Bug, denn die Felder werden ja korrekt in das lokale DataSet geschrieben. Daß dieses die Felder nicht in die DB zurückschreibt hat mit CopyDataSet gar nichts zu tun, sondern trifft ja auch für andere Änderungen an diesen Feldern zu.

Kostas 4. Aug 2015 15:44

AW: FireDac CopyDataSet kopiert nicht den PK
 
Hallo Uwe,

ich konnte jetzt nachstellen das die Ursache wie du schon sagtest nicht CopyDataSet ist sondern FireDac und dessen Query.
Ich habe in meinem Code nachgeschaut wo ich CopyDataSet verwende.
Es ist immer so das ich ein DataSet über einen DataSnap Server bekomme
und diesen in einer MemTable oder direkt verarbeite. Ich schreibe
also nie über die Query in die DB. Deshalb hat es bis jetzt funktioniert.
Dass die Query mein übergebener PK einfach ignoriert war mir nicht
klar. Ich habe all die Jahre IBO verwendet und da ist es nicht so.
Wenn ich ein PK(AutoInc) Feld ein Wert übergebe, wird dieser auch zur
Datenbank transportiert, ansonsten feuert er selbst den Generator
unmittelbar vor dem Schrieben in die DB.

Das war jetzt für mich eine sehr sehr wichtige Lehrstunde.
Tausend Dank nochmals Uwe.



Delphi-Quellcode:
function TForm1.MyCopyDataSet(Qu,Zi:TFDQuery):Boolean;
var n:Integer;
begin
  Qu.First;
  while not Qu.Eof do
  begin
    Zi.Insert;
    for n:=0 to Qu.FieldCount-1 do
    begin
      Zi.FieldByName(Qu.Fields[n].FieldName).value := Qu.Fields[n].value;
    end;
    Zi.Post;
    Qu.next;
  end;
  result:=true;
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:00 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz