2013-10-14 10 views
9

Gibt es eine Möglichkeit, nur das Detail-DataSet zu aktualisieren, ohne den gesamten Hauptdatensatz neu zu laden?Aktualisieren von verschachtelten DataSets mit poFetchDetailsOnDemand

das ist, was ich bisher versucht habe:

DM.ClientDataSet2.Refresh;  
DM.ClientDataSet2.RefreshRecord; 

ich auch versucht:

DM.ClientDataSet1.Refresh; 

Aber die Methode oben frischt das gesamte Master-Daten-Set, nicht nur den aktuellen Datensatz.

Nun scheint der folgende Code, etwas zu tun:

DM.ClientDataSet1.RefreshRecord; 

Gibt es eine Abhilfe oder eine richtige Art und Weise zu tun, was ich will? (Vielleicht ein Zwischen ...)

Zusätzliche Information:

ClientDataSet1 = Master Dataset

ClientDataSet2 = DataSet Detail, ist die folgende: *

object ClientDataSet2: TClientDataSet 
    Aggregates = <> 
    DataSetField = ClientDataSet1ADOQuery2 
    FetchOnDemand = False 
    ..... 
end 

Provider Eigenschaften :

object DataSetProvider1: TDataSetProvider 
    DataSet = ADOQuery1 
    Options = [poFetchDetailsOnDemand] 
    UpdateMode = upWhereKeyOnly 
    Left = 24 
    Top = 104 
    end 
+0

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. –

+0

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

+0

Nicht 100% sicher aber so scheint es. Wie auch immer, welches Problem haben Sie beim Aktualisieren des Hauptdatensatzes? –

Antwort

2

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; 
+0

Schön, ich werde testen und komme bald mit weiteren Kommentaren dazu zurück. – EProgrammerNotFound

Verwandte Themen