Googling findet zahlreiche Artikel, die besagen, dass es bei verschachtelten ClientDataSets überhaupt nicht möglich ist, die Master-CDS zu schließen und wieder zu öffnen, was das OP in diesem Fall nicht tun möchte. Allerdings ...
Die kurze Antwort auf die q ist ja, in dem relativ einfachen Fall, den ich getestet habe, und es ist ziemlich einfach, wenn ein bisschen langatmig; Die notwendigen Schritte richtig zu machen dauerte eine Weile, um herauszufinden.
Der Code ist unten und enthält Kommentare, die erklären, wie es funktioniert und ein paar mögliche Probleme und wie es umgeht oder umgeht. Ich habe es nur mit TAdoQueries getestet, die den CDS-Provider füttern.
Als ich begann, mich in dem alles, es wurde bald klar, dass mit dem üblichen Master + Detail Set-up, obwohl Provider + CDSs ist glücklich, die Stammdaten aus dem Server zu aktualisieren, werden sie einfach nicht die auffrischen Detail Datensätze, sobald sie zum ersten Mal seit dem Öffnen des cdsMasters vom Server gelesen wurden. Dies kann natürlich von Entwurf sein.
Ich glaube nicht, dass ich einen DFM veröffentlichen muss, um mit dem Code zu gehen. Ich habe einfach AdoQueries in der üblichen Master-Detail-Art eingerichtet (mit der Detailabfrage, die die PK des Masters als Parameter hat), einen DataSetProvider auf die Master-AdoQuery, eine Master-CDS auf den Provider und ein Detail-cDS auf die DataSetField des cdsMaster. Um zu experimentieren und zu sehen, was passiert, gibt es für jeden dieser Datasets DBGrids und DBNavigators.
Kurz gesagt, die Funktionsweise des folgenden Codes besteht darin, den AdoQuery-Master und den CDS-Masterdown vorübergehend auf die aktuelle Zeile zu filtern und dann eine Aktualisierung ihrer Daten und der dtail-Daten für die aktuelle Masterzeile zu erzwingen. Anders als bei allen anderen, die ich ausprobiert habe, führt dies dazu, dass die Detailzeilen, die im cdsMaster-Feld DataSet verschachtelt sind, aktualisiert werden.
Btw, die anderen Sackgassen, die ich versuchte, enthalten mit und ohne poFetchDetailsOnDemand auf True gesetzt, ditto cdsMaster.FetchDetailsOnDemand. Offensichtlich bedeutet "FetchDetailsOnDemand" nicht ReFetchDetailsOnDemand!
Ich lief in ein Problem oder zwei meine „Lösung“ arbeiten bekommen, die stickiest eines in dieser Frage SO beschrieben werden: (!) Refreshing a ClientDataSet nested in a DataSetField
prüfe Ich habe, dass diese korrekt mit einem SQL Server arbeitet 2000 Back-End, einschließlich Abrufen von Zeilendatenänderungen, die auf dem Server von ISqlW abgefeuert wurden. Ich habe auch überprüft, mit Sql Server Profiler, dass der Netzwerkverkehr in einer Aktualisierung bezieht sich nur auf die einzelnen Master-Zeile und ihre Details.
Delphi 7 + Win7 64-Bit, btw.
procedure TForm1.cdsMasterRowRefresh(MasterPK : Integer);
begin
// The following operations will cause the cursor on the cdsMaster to scroll
// so we need to check and set a flag to avoid re-entrancy
if DoingRefresh then Exit;
DoingRefresh := True;
try
// Filter the cdsMaster down to the single row which is to be refreshed.
cdsMaster.Filter := MasterPKName + ' = ' + IntToStr(MasterPK);
cdsMaster.Filtered := True;
cdsMaster.Refresh;
Inc(cdsMasterRefreshes); // just a counter to assist debugging
// release the filter
cdsMaster.Filtered := False;
// clearing the filter may cause the cdsMaster cursor to move, so ...
cdsMaster.Locate(MasterPKName, MasterPK, []);
finally
DoingRefresh := False;
end;
end;
procedure TForm1.qMasterRowRefresh(MasterPK : Integer);
begin
try
// First, filter the AdoQuery master down to the cdsMaster current row
qMaster.Filter := MasterPKName + ' = ' + IntToStr(MasterPK);
qMaster.Filtered := True;
// At this point Ado is happy to refresh only the current master row from the server
qMaster.Refresh;
// NOTE:
// The reason for the following operations on the qDetail AdoQuery is that I noticed
// during testing situations where this dataset would not be up-to-date at this point
// in the refreshing operations, so we update it manually. The reason I do it manually
// is that simply calling qDetail's Refresh provoked the Ado "Insufficient key column
// information for updating or refreshing" despite its query not involving a join
// and the underlying table having a PK
qDetail.Parameters.ParamByName(MasterPKName).Value := MasterPK;
qDetail.Close;
qDetail.Open;
// With the master and detail rows now re-read from the server, we can update
// the cdsMaster
cdsMasterRowRefresh(MasterPK);
finally
// Now, we can clear the filter
qMaster.Filtered := False;
qMaster.Locate(MasterPKName, MasterPK, []);
// Obviously, if qMaster were filtered in the first place, we'd need to reinstate that later on
end;
end;
procedure TForm1.RefreshcdsMasterAndDetails;
var
MasterPK : Integer;
begin
if cdsMaster.ChangeCount > 0 then
raise Exception.Create(Format('cdsMaster has %d change(s) pending.', [cdsMaster.ChangeCount]));
MasterPK := cdsMaster.FieldByName(MasterPKName).AsInteger;
cdsDetail.DisableControls;
cdsMaster.DisableControls;
qDetail.DisableControls;
qMaster.DisableControls;
try
try
qMasterRowRefresh(MasterPK);
except
// Add exception handling here according to taste
// I haven't encountered any during debugging/testing so:
raise;
end;
finally
qMaster.EnableControls;
qDetail.EnableControls;
cdsMaster.EnableControls;
cdsDetail.EnableControls;
end;
end;
procedure TForm1.cdsMasterAfterScroll(DataSet: TDataSet);
begin
RefreshcdsMasterAndDetails;
end;
procedure TForm1.cdsMasterAfterPost(DataSet: TDataSet);
// NOTE: The reason that this, in addition to cdsMasterAfterScroll, calls RefreshcdsMasterAndDetails is
// because RefreshcdsMasterAndDetails only refreshes the master + detail AdoQueries for the current
// cdsMaster row. Therefore in the case where the current cdsMaster row or its detail(s)
// have been updated, this row needs the refresh treatment before we leave it.
begin
cdsMaster.ApplyUpdates(-1);
RefreshcdsMasterAndDetails;
end;
procedure TForm1.btnRefreshClick(Sender: TObject);
begin
RefreshcdsMasterAndDetails;
end;
procedure TForm1.cdsDetailAfterPost(DataSet: TDataSet);
begin
cdsMaster.ApplyUpdates(-1);
end;
AFAIK, in verschachtelten Client-Datasets können Sie 'Refresh' nicht für das Detail-Dataset verwenden. Überprüfen Sie diesen [Artikel] (http://edn.embarcadero.com/article/29825), der von Cary Jensen geschrieben wird, und suchen Sie nach dem Refresh-Wort. –
Im verknüpften Artikel sagte der Autor, dass ich ein Dataset ohne Dataset-Provider nicht aktualisieren kann. OK. Also, ist die einzige Möglichkeit, den gesamten Master-Datensatz zu aktualisieren? – EProgrammerNotFound
Nicht 100% sicher aber so scheint es. Wie auch immer, welches Problem haben Sie beim Aktualisieren des Hauptdatensatzes? –