Zwischenspeichern von Aktualisierungen (FireDAC)

Aus RAD Studio
Wechseln zu: Navigation, Suche

Nach oben zu Bearbeiten von Daten (FireDAC)

Allgemeine Informationen

Im Modus "Zwischenspeicherte Aktualisierungen" können Aktualisierungen in eine Datenbank zu einem späteren Zeitpunkt eingetragen werden, anstatt die Methoden Post/Delete aufzurufen. Damit wird das Eintragen mehrerer Aktualisierungen in einem einzigen Stapel, optional in einer Transaktion, ermöglicht.

Setzen Sie die Eigenschaft CachedUpdates auf True, um eine Datenmenge in den Modus "Zwischenspeicherte Aktualisierungen" zu versetzen. Die Datenmenge verfolgt dann alle Änderungen, die nach dem letzten Setzen dieser Eigenschaft auf True oder den letzten Aufrufen von CancelUpdates/CommitUpdates vorgenommen wurden. Diese Änderungen werden in das Änderungsjournal aufgenommen, in dem alle Änderungen nach der Uhrzeit, zu der eine Änderung vorgenommen wurde, sortiert sind. FireDAC verfolgt nicht mehrere Versionen desselben Datensatzes. Die letzte Änderung überschreibt die vorherigen und verschiebt den Datensatz an das Ende der Änderungsreihenfolge.

FireDAC unterstützt die Modi "Dezentralisiert" und "Zentralisiert" für zwischengespeicherte Aktualisierungen:

  • Dezentralisierte zwischengespeicherte Aktualisierungen – jede Datenmenge protokolliert die Änderungen unabhängig von anderen Datenmengen. Dies ist der klassische und Standardmodus.
  • Zentralisierte zwischengespeicherte Aktualisierungen – mehrere Datenmengen nutzen ein einziges Änderungsprotokoll gemeinsam, und die Änderungen werden chronologisch protokolliert.

Zentralisierte zwischengespeicherte Aktualisierungen

Wenn eine Anmeldung der Anwendung erfolgen muss und Änderungen aus mehreren Datenmengen in chronologischer Reihenfolge eintragen werden müssen, können "zentralisierte zwischengespeicherte Aktualisierungen" verwendet werden. Dazu muss der Eigenschaft SchemaAdapter eine einzelne TFDSchemaAdapter-Instanz der Datenmengen zugewiesen werden. TFDSchemaAdapter dient für mehrere Datenmengen als zentraler Speicher für die Zeilen und deren Änderungen.

Zentralisierte zwischengespeicherte Aktualisierungen sind in Haupt/Detail-Beziehungen nützlich, bei denen eine Hauptdatenmenge Änderungen stufenweise an die Detaildatenmengen, einschließlich von Zählerfeldwerten (Auto-Inkrementierung), weitergibt. Damit die Weitergabe an eine Detaildatenmenge aktiviert wird, muss FetchOptions.DetailCascade auf True gesetzt sein. Dies ermöglicht Folgendes:

  • Synchronisierte Haupt/Detailänderungen; die Änderungen der Haupt- und Detaildatenmengen werden aufgezeichnet und chronologisch übernommen. Zum Beispiel: Zuerst kommt der eingefügte Hauptdatensatz, dann die einfügten zugehörigen Detaildatensätze.
  • Weitergabe eines Wertes der Identitätsspalte von der Hauptdatenmenge an eine Detaildatenmenge. Zum Beispiel: Wenn eine Detaildatenmenge mit einer Identitätsspalte der Hauptdatenmenge verknüpft ist und Sie Aktualisierungen anwenden, müssen die zugehörigen Detaildatensätze den tatsächlichen Wert der Identitätsspalte der Hauptdatenmenge erhalten.
  • Stufenweises Löschen von Detaildatensätzen, wenn ein Hauptdatensatz gelöscht wird. Zum Beispiel: Wenn ein Hauptdatensatz gelöscht wird, dann werden auch alle zugehörigen Detaildatensätze gelöscht, und dieser Vorgang wird in das Änderungsprotokoll eingetragen.
  • Stufenweise Weitergabe der Feldänderungen der Hauptdatenmenge an eine Detaildatenmenge.

Die Weitergabe erfolgt, wenn die folgenden Bedingungen erfüllt sind:

Sie können auch mit DetailServerCascade steuern, ob FireDAC clientseitige stufenweise Änderungen in die Datenbank einträgt. DetailServerCascade wird zusammen mit FetchOptions.DetailCascade verwendet.

Führen Sie die folgenden Schritte aus (richten Sie zuerst die bereichsbasierte H/D ein, und setzen Sie die Eigenschaft CachedUpdates auf True), um zentralisierte zwischengespeicherte Aktualisierungen mit Weitergabe zu aktivieren:

  1. Ziehen Sie eine TFDSchemaAdapter-Komponente auf ein Formular.
  2. Setzen Sie die Eigenschaft SchemaAdapter der Hauptdatenmenge auf TFDSchemaAdapter.
  3. Setzen Sie die Eigenschaft SchemaAdapter der Detaildatenmenge auf TFDSchemaAdapter.
  4. Setzen Sie FetchOptions.DetailCascade der Detaildatenmenge auf True.

Dadurch wird gleichzeitig eine referenzielle Einschränkung im Arbeitsspeicher für eine Detaildatenmenge aktiviert. Dies einspricht einer SQL-Anweisung:

ALTER TABLE <detail> ADD CONSTRAINT
FOREIGN KEY (<detail fields>)
REFERENCES <master> (<master fields>)
ON DELETE CASCADE
ON UPDATE CASCADE

Zum Übernehmen von Aktualisierungen sollte die Anwendung die Methode TFDSchemaAdapter.ApplyUpdates anstatt der Methode ApplyUpdates der Datenmenge verwenden. Beheben Sie Fehler mit der Methode TFDSchemaAdapter.Reconcile anstatt mit der Methode Reconcile der Datenmenge.

Weitere Einzelheiten finden Sie unter dem Beispiel Centralized Cached Updates.

Verfolgen von Aktualisierungen

Wenn Ihre Anwendung im Modus "Zwischengespeicherte Aktualisierungen" arbeitet, können Sie die Änderungen verfolgen und optional die Änderungen jeder Datenmenge zurücksetzen. Verwenden Sie die folgenden Eigenschaften, um Änderungen zu verfolgen:

  • UpdatesPending – gibt True zurück, wenn das Änderungsprotokoll nicht leer ist.
  • ChangeCount – gibt die Gesamtanzahl der Änderungen zurück.
  • UpdateStatus – gibt die Änderungsart für den aktuellen Datensatz zurück.
  • FilterChanges – ermöglicht das Filtern von Datensätzen nach Änderungsart.

Verwenden Sie die folgenden Eigenschaften und Methoden, um bestehende Änderungen zurückzusetzen:

  • SavePoint – setzt/ermittelt den aktuellen Status des Änderungsprotokolls.
  • RevertRecord – setzt den aktuellen Datensatz auf den vorherigen (ursprünglichen) Status zurück.
  • UndoLastChange – wechselt zum zuletzt geänderten Datensatz und setzt ihn auf den vorherigen (ursprünglichen) Status zurück.
  • CancelUpdates – setzt alle Datensätze im Änderungsprotokoll zurück.

Um beispielsweise eine einfache "Rückgängig"-Funktionalität zu implementieren, können Sie eine actUndo-Aktion erstellen und die folgenden Ereignisbehandlungsroutinen zuweisen:

procedure TForm1.actUndoUpdate(Sender: TObject);
begin
  actUndo.Enabled := FDQuery1.UpdatesPending;
end;

procedure TForm1.actUndoExecute(Sender: TObject);
begin
  FDQuery1.UndoLastChange(True);
end;

Sie können den folgenden Code verwenden, um Transaktionen im Arbeitsspeicher zu implementieren, die auch die Möglichkeit umfassen, eine Gruppe von Änderungen rückgängig zu machen:


FDQuery1.CachedUpdates := True;
iSavePoint := FDQuery1.SavePoint;
try
  FDQuery1.Append;
  ...
  FDQuery1.Post;
  FDQuery1.Append;
  ...
  FDQuery1.Post;
  FDQuery1.Append;
  ...
  FDQuery1.Post;
except
  FDQuery.SavePoint := iSavePoint;
end;

Hinweis: Im Modus "Zwischengespeicherte Aktualisierungen" arbeiten die folgenden Methoden und Eigenschaften mit dem Aktualisierungsjournal zusammen:

  • Die Eigenschaft Data schließt alle Datensätze, auch gelöschte, und deren Änderungen ein.
  • Die Eigenschaft Delta gibt die gelöschten, eingefügten oder aktualisierten Datensätze im Aktualisierungsjournal zurück.
  • Die Methoden CopyRecord und CopyDataSet erstellen neue Änderungen und kopieren das Änderungsjournal nicht.
  • LoadFromStream, LoadFromFile, SaveToStream und SaveToFile laden/speichern Daten mit dem Aktualisierungsjournal.

Im Modus "Zwischengespeicherte Aktualisierungen" lösen einige Methoden oder Eigenschaftseinstellungen eine Exception aus, wenn Änderungen im Aktualisierungsjournal vorhanden sind. Diese Änderungen müssen übergeben oder abgebrochen werden. Dies sind:

  • Refresh
  • Setzen von CachedUpdates auf False


Anwenden von Aktualisierungen

Verwenden Sie die Methode ApplyUpdates, um Aktualisierungen in eine Datenbank einzutragen. Wenn beim Eintragen eines Datensatzes eine Exception ausgelöst wird, dann wird sie dem Datensatz zugeordnet. Beachten Sie, dass die Methode ApplyUpdates:

  • Keine Exception auslöst, sondern die Anzahl der ausgelösten Exceptions zurückgibt.
  • Das Eintragen von Aktualisierungen nicht in einer Transaktion kapselt; dies kann von einer Anwendung ausgeführt werden.
  • Dieselbe Logik für das Eintragen von Aktualisierungen verwendet wie direkte Aktualisierungen.

Nach dem Eintragen von Aktualisierungen verbleiben die Datensätze weiterhin im Änderungsprotokoll. Rufen Sie die Methode CommitUpdates auf, um diese Datensätze aus dem Änderungsprotokoll zu entfernen und sie als unverändert zu kennzeichnen. Zum Beispiel:

FDQuery1.CachedUpdates := True;
FDQuery1.Append;
...
FDQuery1.Post;
FDQuery1.Append;
...
FDQuery1.Post;
FDQuery1.Append;
...
FDQuery1.Post;
FDConnection1.StartTransaction;
iErrors := FDQuery1.ApplyUpdates;
if iErrors = 0 then begin
  FDQuery1.CommitUpdates;
  FDConnection1.Commit;
end
else
  FDConnection1.Rollback;

Hinweis: Dieser Fall entspricht dem erwarteten Verhalten, wenn AutoCommitUpdates auf False gesetzt ist.

  • Wenn Sie AutoCommitUpdates auf True setzen, dann müssen Sie CommitUpdates nicht explizit aufrufen, weil alle durch den Aufruf von ApplyUpdates erfolgreich aktualisierten Datensätze automatisch als unverändert gekennzeichnet werden.

Überprüfen von Fehlern

Wenn im Aufruf von ApplyUpdates ein Fehler auftritt, dann zeichnet ApplyUpdates den Fehler in der internen Datensatzstruktur auf und fährt mit der Verarbeitung der Aktualisierungen fort, bis die Anzahl an Fehlern gleich oder größer AMaxErrors ist. ApplyUpdates löst keine Exceptions aus. Um alle fehlerhaften Datensätze nach dem Aufruf von ApplyUpdates zu verarbeiten, verwenden Sie den Abgleichungsprozess oder Filter für die fehlerhaften Datensätze.

Weisen Sie die Ereignisbehandlungsroutine OnReconcileError zu, und rufen Sie die Methode Reconcile auf, um Datensätze abzugleichen. Die Ereignisbehandlungsroutine OnReconcileError ermöglicht die Analyse des Fehlers sowie das Lesen und Ändern des Wertes des aktuellen Datensatzfeldes. Beim Beenden sollte die Ereignisbehandlungsroutine eine Aktion zuweisen, die der FireDAC-Code für den aktuellen Datensatz mit dem Fehler übernehmen soll. Nach dem Aufruf der Methode Reconcile kann ApplyUpdates erneut aufgerufen werden, um zu versuchen, die fehlerhaften Datensatzänderungen einzutragen.

Nehmen Sie rtHasErrors in FilterChanges auf, um fehlerhafte Datensätze zu filtern. Navigieren Sie dann durch die Datenmenge, und ermitteln Sie durch Abrufen der Eigenschaft RowError ein dem aktuellen Datensatz zugeordnetes Exception-Objekt. Zum Beispiel:

var
  oErr: EFDException;
...
if FDQuery1.ApplyUpdates > 0 then begin
  FDQuery1.FilterChanges := [rtModified, rtInserted, rtDeleted, rtHasErrors];
  try
    FDQuery1.First;
    while not FDQuery1.Eof do begin
      oErr := FDQuery1.RowError;
      if oErr <> nil then begin
        // process exception object
        ...
      end;
      FDQuery1.Next;
    end;
  finally
    FDQuery1.FilterChanges := [rtUnmodified, rtModified, rtInserted];
  end;
end;

Siehe auch

Beispiele