![]() |
Dataset ADOQuery in ein Clientdataset kopieren
Hallo die Damen und Herren,
mich beschäftigt seit geraumer Zeit ein triviales Problem wie ich vermute. Ich habe eine ADOQuery, gefüllt mit Daten und möchte diese an ein Clientdataset übergeben. Dies gelingt aus nicht nachvollziebaren Gründen nicht. Eine Variante wäre Folgende:
Delphi-Quellcode:
Habe schon eine ganze Menge verschiedene Variante probiert aber es klappt nicht.
procedure TDataContainer.fillupdataset;
var i : Integer; s : String; TempProvider : TDataSetProvider; ClientDataSet1 : TClientDataSet; begin ClientDataSet1 := TClientDataSet.Create(nil); TempProvider := TDataSetProvider.Create(nil); TempProvider.DataSet := fDataContainerDbThread.ADOQuery; i := TempProvider.DataSet.RecordCount; // ist in Ordnung, i ist größer 0 ClientDataSet1.Data := TempProvider.Data; i := ClientDataSet1.RecordCount; // hier ist in i immer 0. Die Übergabe klappt nicht TempProvider.Free; end; Was ist der einfachste Weg, Daten in ein CDS zu duplizieren? Auch wenn ich das CDS mit einem Provider verknüpfe gibt es nicht den gewünschten Erfolg. Zusatzfrage: Alle Komponenten werden in Runtime Created. Welchen Owner kann man hier angeben. Dieser Sollte vom Typ TComponent sein, aber TComponent habe ich nicht, da es keine Formularanwendung ist :| Viele Grüße und vielen Dank |
AW: Dataset ADOQuery in ein Clientdataset kopieren
Moin, ich mache das mit dieser proc. TDM ist einfach nur mein DataModule
Delphi-Quellcode:
procedure TDM.CopyDataSetToCDS(Source: TDataSet; Dest: TClientDataSet; CloseSource: boolean);
var dsProvider: TDataSetProvider; begin {GetText in der Source funktioniert nicht} {Filter in der Source funktioniert} dsProvider:=TDataSetProvider.Create(nil); try dsProvider.DataSet:=Source; Dest.SetProvider(dsProvider); Dest.Open; finally FreeAndNil(dsProvider); end; if CloseSource then Source.Close; end; |
AW: Dataset ADOQuery in ein Clientdataset kopieren
Besten Dank für dein Feedback.
Ich habe eine kleine Demo gemacht und bekomme die gleichen Probleme wie vorher
Delphi-Quellcode:
Ich erwarte an der Stelle
unit DM;
interface uses System.SysUtils, System.Classes, Datasnap.Provider, Data.DB, Datasnap.DBClient; type TDataModule1 = class(TDataModule) cds1: TClientDataSet; private { Private-Deklarationen } public { Public-Deklarationen } procedure testemal(ds : TDataSet); procedure CopyDataSetToCDS(Source: TDataSet; Dest: TClientDataSet; CloseSource: boolean); end; var DataModule1: TDataModule1; implementation {%CLASSGROUP 'System.Classes.TPersistent'} {$R *.dfm} procedure TDataModule1.testemal(ds : TDataSet); var a : Integer; begin a := ds.RecordCount; // in a steht 17, das ist auch korrekt DataModule1.CopyDataSetToCDS( ds, cds1, false ); a := cds1.RecordCount; // in a steht 0. Der Übertrag hat nicht geklappt?! end; procedure TDataModule1.CopyDataSetToCDS(Source: TDataSet; Dest: TClientDataSet; CloseSource: boolean); var dsProvider: TDataSetProvider; begin {GetText in der Source funktioniert nicht} {Filter in der Source funktioniert} dsProvider:=TDataSetProvider.Create(nil); try dsProvider.DataSet:=Source; Dest.SetProvider(dsProvider); Dest.Open; finally FreeAndNil(dsProvider); end; if CloseSource then Source.Close; end; end.
Delphi-Quellcode:
das in a die gleiche Anzahl der Records enthalten ist, wie im dataset ds.
a := cds1.RecordCount
Habe ich hier irgendeinen Gedankenfehler? Das ganze ist in einem Datamodul und die CDS liegt auf der Form. Der Aufruf von testemal kommt von aussen, aber im dataset ds ist injedemfall Inhalt. Es bleibt spannend :roll: |
AW: Dataset ADOQuery in ein Clientdataset kopieren
Nach ewigen probieren bin ich zu einer Variante gelangt die anscheinend funktioniert. Es ist mir allerdings ein totales Rätsel warum das so ist.
Delphi-Quellcode:
Wenn exakt an der Stelle oben im Code
procedure TDataModule1.CopyDataSetToCDS(Source: TDataSet; var Dest: TClientDataSet; CloseSource: boolean);
var dsProvider: TDataSetProvider; I: Integer; a: Boolean; begin {GetText in der Source funktioniert nicht} {Filter in der Source funktioniert} dsProvider:=TDataSetProvider.Create(self); try dsProvider.DataSet:=Source; a := Dest.Data = dsProvider.Data; Dest.SetProvider(dsProvider); Dest.Open; finally FreeAndNil(dsProvider); end; if CloseSource then Source.Close; end; end.
Delphi-Quellcode:
eingefügt wird, dann erhalte ich auch wie erwartet an folgender Stelle den Wert 17
a := Dest.Data = dsProvider.Data;
Delphi-Quellcode:
Allerdings, die zugefügte Codezeile ergibt keinen Sinn.
a := cds1.RecordCount;
Dest.Data ist an der Stelle immer null, a wird immer False. trotzdem passiert irgendwas, dass dazu führt, dass im cds aufeinmal alle Daten drin sind. Ich könnte auch
Delphi-Quellcode:
ergänzen, das hat den selben positiven Effekt.
if Dest.Data = dsProvider.Data then
begin end; Ein Timingproblem scheint es nicht zu sein. Ich habe an der Stelle das Programm durch eine Schleife im Ablauf verzögert. Das hat nichts gebracht. Tja, da weiß ich nicht weiter. Vermutlich fehlt irgendein Schritt mit dem Dest oder dem Provider, der durch die eingefügte Zeile im Hintergrund ausgelöst wird. Viele Grüße und gute Nacht |
AW: Dataset ADOQuery in ein Clientdataset kopieren
Keine Ahnung, was du da gemacht hast. Hier vielleicht noch ein paar Hinweise - zumindest mache ich es so und es funktioniert immer. Bevor der die Copy-Proc aufgerufen wird sollte:
|
AW: Dataset ADOQuery in ein Clientdataset kopieren
Du scheinst, wie Papaschlumpf73 schreibt, auf dem letzten Datensatz zu stehen.
Probiere mal Folgendes aus:
Delphi-Quellcode:
procedure TForm1.CopyDataSetToCDS(Source: TDataSet; Dest: TClientDataSet; CloseSource: boolean);
var dsProvider: TDataSetProvider; inscount: Integer; begin dsProvider := TDataSetProvider.Create(nil); try dsProvider.DataSet := Source; dsProvider.GetRecords(-1, inscount, 0); // !!! Lade alle Records !!! Dest.SetProvider(dsProvider); Dest.Open; finally FreeAndNil(dsProvider); end; if CloseSource then Source.Close; end; |
AW: Dataset ADOQuery in ein Clientdataset kopieren
Ich kann mich nur bei euch bedanken.
Sowohl den Sourcedatensatz auf .First setzen als auch die GetRecords Variante führen zum gewünschten Ergebnis. Soviele verschiedene Varianten die ich probiert habe aber auf die triviale Idee bin ich nicht gekommen. Vielen Lieben Dank an euch! |
AW: Dataset ADOQuery in ein Clientdataset kopieren
Hallo, ich muss euch doch nochmal belästigen.
Grundsätzlich dachte ich, dass es funktioniert. Das tut es auch allerdings nur im ersten Durchlauf. Danach wird das ZielCds nicht erneut aktualisiert. Folgende 2 Varianten habe ich erstellt: Einmal mit einem CDS das global erstellt wurde und bei jedem Durchlauf geleert werden soll:
Delphi-Quellcode:
testCDS_global : TClientDataSet; ... testCDS_global := TClientDataSet.Create(self);
Delphi-Quellcode:
Diese Prozedur füllt das testCds nur beim ersten Durchlauf, sobald das CDS einmal erstellt, gefüllt und beim Durchlauf EmptyDataSet gemacht wurde, dann klappt das nicht mehr.
procedure TDataContainer.fillupdataset;
var a,b : Integer; begin try if testCDS_global.Active then begin testCDS_global.Open; testCDS_global.EmptyDataSet; end; except a:=a; end; try // a = Anzahl der Einträge im ADOquery dataset a := fDataContainerDbThread.ADOQuery.RecordCount; CopyDataSetToCDS( fDataContainerDbThread.ADOQuery, testCDS_global, false ); b := testCDS_global.RecordCount; finally end; end; Folgende Prozedur führt zu einer Aktualisierung bei jedem Durchlauf:
Delphi-Quellcode:
Heißt, es muss einen Unterschied zwischen einem neu createden CDS und einem CDS das mit EmptyDataSet behandelt wurde geben.
procedure TDataContainer.fillupdataset2;
var a,b : Integer; testCDS_lokal : TClientDataSet; begin testCDS_lokal := TClientDataSet.Create(nil); try // a = Anzahl der Einträge im ADOquery dataset a := fDataContainerDbThread.ADOQuery.RecordCount; CopyDataSetToCDS( fDataContainerDbThread.ADOQuery, testCDS_lokal, false ); b := testCDS_lokal.RecordCount; finally FreeAndNil(testCDS_lokal); end; end; Ich komme nicht drauf :cyclops: Vollständigkeitshalber:
Delphi-Quellcode:
Zusatzfrage:
procedure TDataContainer.CopyDataSetToCDS(Source: TDataSet; Dest: TClientDataSet; CloseSource: boolean);
var dsProvider: TDataSetProvider; a,b : Integer; begin dsProvider := TDataSetProvider.Create(nil); try Source.First; dsProvider.DataSet := Source; dsProvider.GetRecords(-1, a, 0); // !!! Lade alle Records !!! Dest.SetProvider(dsProvider); Dest.Open; finally FreeAndNil(dsProvider); end; if CloseSource then Source.Close; end; Wenn die Variable dsProvider auf FreeAndNil gesetzt wird, woher kennt das das Sourcedataset im Anschluss dann noch seinen Provider? Das scheint an dieser Stelle egal zu sein? Der dsProvider ist ja ohnehin nur in dieser Prozedur verfügbar.. |
AW: Dataset ADOQuery in ein Clientdataset kopieren
Das hier ist schon mal nicht so toll.
Delphi-Quellcode:
Wenn das CDS aktiv ist, dann soll er es öffnen? Nein, das kann es nicht sein.
if testCDS_global.Active then
begin testCDS_global.Open; testCDS_global.EmptyDataSet; end; Das würde ich erstmal ändern in:
Delphi-Quellcode:
Dann hast du für die Copy-proc ein leeres, geschlossenes ClientDataSet.
if testCDS_global.Active then
begin testCDS_global.EmptyDataSet; testCDS_global.Close; end; |
AW: Dataset ADOQuery in ein Clientdataset kopieren
An der Stelle habe ich auch schon probiert. Ich bekomme beim Close immer einen "schwerwiegenden Fehler" angezeigt.
Aus diesem Grund habe ich das Close wieder entfernt. Aber grundsätzlich macht das Sinn was du schreibst. |
AW: Dataset ADOQuery in ein Clientdataset kopieren
Um den schwerwiegenden Fehler beim close zu beseitigen habe ich nun den dsProvider in CopyDataSetToCDS auch global hinterlegt (so wie das cds).
Jetzt scheint es so abzulaufen wie ich mir das wünsche. Ich hoffe das war es :spin2: |
AW: Dataset ADOQuery in ein Clientdataset kopieren
Wenn du die globale Variante nimmst, solltest du unbedingt LogChanges:=false für das Clientdataset direkt nach dessen Create aufrufen. Das verhindert, dass alle Änderungen protokolliert werden und der Arbeitsspeicher immer voller wird.
|
AW: Dataset ADOQuery in ein Clientdataset kopieren
Besten Dank, habe es mit eingebaut.
:thumb: |
AW: Dataset ADOQuery in ein Clientdataset kopieren
Moin...8-)
[nur meine Meinung] Der Hickack mit dem CDS, und ADO als solches :zwinker:, riecht für mich nach "Workaround". :? Zitat:
|
AW: Dataset ADOQuery in ein Clientdataset kopieren
Auch wenn die Frage jetzt nicht an mich ging: In unseren Datenbanken müssen die Daten einiger Tabellen verschlüsselt werden - so dass auch die IT nicht dran kommt. Diese Daten werden in der Delphi-Anwendung per FeldSetText/FieldGetText während des Schreibens oder Lesens ver- bzw. entschlüsselt. So werden die Daten immer sauber angezeigt und man muss sich nicht weiter um die Verschlüsselung kümmern. Wenn man aber nach Textfeldern filtern oder im Grid sortieren will, stört die Verschlüsselung. In solchen Fällen kopiere ich die Daten in ein CDS und entschlüssele dort zunächst alle Datensätze lokal.
|
AW: Dataset ADOQuery in ein Clientdataset kopieren
Ich nutze das CDS nur um Daten zwischenzuspeichern. Ein DB Thread läuft, führt in regelmäßigen Abständen eine Datenbankabfrage durch und speichert die geladenen Daten threadsicher im CDS. Anschließend gibt es andere, die auf das CDS zugreifen und die Daten in Ihren eigenen Wirkungsbereich kopieren und damit arbeiten. Ich vermeide damit, dass jeder einzelne auf die Datenbank zugreift und erhoffe mir damit eine verbesserte performance. Außerdem bringt ein CDS von Haus aus ganz nette Features mit. Das ganze im XE2.
Das mit der Verschlüsselung hatte ich auch schon mal durchdacht. Danke für den Input. Damit ist der Punkt filtern und suchen tatsächlich möglich. Dies war auch bei mir ein Störfaktor beim Durchdenken :thumb: |
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:17 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-2025 by Thomas Breitkreuz