Undo in Formularen und Unterformularen

André Minhorst, Duisburg

Die Verwendung von Formularen und Unterformularen ist ein probates Mittel zur Darstellung von Daten aus 1:n- und m:n-Beziehungen. Dabei tritt immer wieder das ärgernis zu Tage, dass Access von Haus aus keine Möglichkeit mitbringt, änderungen an den Daten im Unterformular in einem Schritt mit denen des Hauptformulars rückgängig zu machen. Dieser Beitrag stellt eine Lösung vor, wie die Benutzer einer Datenbank dennoch mit einem Mausklick komplexe änderungen rückgängig machen können.

Hinweis

Die Beispieldatenbanken zu diesem Beitrag heißen Forms.mdb und FormsAndSubforms.mdb. Sie finden die Datenbanken auf der Heft-CD oder im Internet unter http://www.access-im-unternehmen.de unter dem Shortlink 276. Nützliche Informationen gibt es im Beitrag Transaktionen in Access, Shortlink 275.

Der Einsatz von Haupt- und Unterformularen ist durch die Verknüpfung der Datenherkünfte dieser beiden sehr hilfreich, ermöglicht er doch die Bearbeitung zusammenhängender Daten wie beispielsweise Bestellungen und bestellter Artikel (siehe Bild 1).

Bild 1: Anzeige von Bestelldaten in Haupt- und Unterformular

Leider lassen diese Formulare eine sehr wichtige Eigenschaft vermissen: Sie bieten keine Undo-Funktion, die alle seit dem Anzeigen des Datensatzes im Hauptformular getätigten änderungen rückgängig macht. Es reicht gerade zu einer Undo-Funktion für den im Hauptformular angezeigten Datensatz. Wenn man einmal versehentlich den Hauptformular-Datensatz wechselt und änderungen an den Datensätzen im Unterformular vornimmt, ist dort maximal der letzte bearbeitete Datensatz noch zu retten. Den Rest können Sie aus dem Gedächtnis reproduzieren.

Wenn Sie nicht aus Sicherheitsgründen vor jeder Verwendung solcher Formulare eine Kopie der Datenbank anlegen möchten, lesen Sie weiter: Zum Warmmachen erfahren Sie zunächst, wie Sie änderungen in einem einfachen Formular vom öffnen des Formulars an verwerfen können, und dann geht es an die Unterformulare: Hier lernen Sie, wie Sie alle änderungen am aktuellen Datensatz des Hauptformulars und den verknüpften Datensätzen des Unterformulars mit einem Mausklick rückgängig machen – wenn Sie den Datensatz nicht zwischenzeitlich verlassen oder gespeichert haben.

Abhilfe schafft die Verwendung so genannter Transaktionen, mit denen man eine Abfolge von Datenbankaktionen zusammenfassen und entweder komplett übernehmen oder wieder verwerfen kann.

Hinweis

Der Beitrag Transaktionen in Access in der vorliegenden Ausgabe von Access im Unternehmen (oder unter http://www.access-im-unternehmen.de, Shortlink 275) beschreibt im Detail, wie Transaktionen funktionieren und wie man sie einsetzen kann.

Die wichtigsten Merkmale von Transaktionen in diesem Zusammenhang sind die, dass alle innerhalb einer Transaktion zu berücksichtigenden Vorgänge im Kontext eines Workspace-Objekts (DAO) oder eines Connection-Objekts (ADO) erfolgen müssen und dass alle auf diese Weise durchgeführten änderungen entweder komplett zu speichern oder komplett zu verwerfen sind.

Die Beispieldatenbanken enthalten zwei sehr einfach aufgebaute Tabellen. Die erste heißt tblKunden und enthält neben dem Primärschlüsselfeld KundeID lediglich das Feld Kundenname. Die zweite Tabelle heißt tblProjekte und besteht aus den Feldern ProjektID, Projekt und KundeID. Letzteres ist ein Fremdschlüsselfeld für die Verknüpfung mit der Tabelle tblKunden.

Hinweis

Die hier vorgestellten Techniken funktionieren nur unter Access 2000 und höher.

Bereits bei der Arbeit mit einem Formular kann es sinnvoll sein, alle seit dem öffnen des Formulars durchgeführten änderungen wieder rückgängig zu machen. Wie das funktioniert, erfahren Sie in nachfolgendem Beispiel.

Das hier verwendete Formular basiert auf der Tabelle tblKunden und zeigt lediglich die beiden Felder dieser Tabelle an (siehe Bild 2). Zusätzlich enthält das Formular eine Schaltfläche namens cmdOK und eine namens cmdAbbrechen.

Letztere soll dafür sorgen, dass alle seit dem öffnen des Formulars durchgeführten änderungen verworfen werden.

Bis Access 2000 gab es keine Möglichkeit, die während der Arbeit mit einem Formular ablaufenden Aktionen in einer Transaktion zusammenzufassen. Der Grund sind die bereits weiter oben beschriebenen Workspace- beziehungsweise Connection-Objekte, in deren Kontext die Transaktion abläuft. Gebundene Formulare arbeiten Datenoperationen außerhalb der üblichen Bereiche ab, sodass sich dort keine Transaktion starten lässt.

Bild 2: Beispielformular für das formularweite Undo

Der Unterschied ab Version 2000, der dies erlaubt, ist die Möglichkeit der Verwendung von Recordset-Objekten als Datenherkunft von Formularen.

Das Beispielformular ist derzeit noch an die Tabelle tblKunden gebunden, da Sie diese Tabelle als Datenherkunft des Formulars festgelegt haben.

Ab Access 2000 können Sie das Formular auch an ein Recordset-Objekt binden, das die Daten dieser Tabelle enthält.

Um das nachzuvollziehen, leeren Sie einfach die Eigenschaft Datenherkunft des Formulars und legen für die Ereigniseigenschaft die Prozedur aus Quellcode 1 an.

Private Sub Form_Open(Cancel As Integer)
    Dim db As DAO.Database
    Dim rst As DAO.Recordset
    Set db = CurrentDb
    Set rst = db.OpenRecordset _        ("tblKunden", dbOpenDynaset)
    Set Me.Recordset = rst
End Sub

Quellcode 1

Wenn Sie das Formular erneut öffnen, stellen Sie fest, dass es wie vorher die gewünschten Daten anzeigt.

Private Sub Form_Delete(Cancel As Integer)
    If bolDirty = False Then
        bolDirty = True
        DBEngine.BeginTrans
    End If
End Sub
Private Sub Form_Dirty(Cancel As Integer)
    If bolDirty = False Then
        bolDirty = True
        DBEngine.BeginTrans
    End If
End Sub

Quellcode 2

Private Sub cmdOK_Click()
    DoCmd.RunCommand acCmdSaveRecord
    If bolDirty = True Then
        DBEngine.CommitTrans
    End If
    DoCmd.Close acForm, Me.Name
End Sub

Quellcode 3

Private Sub cmdAbbrechen_Click()
    If bolDirty = True Then
        DBEngine.Rollback
    End If
    DoCmd.Close acForm, Me.Name
End Sub

Quellcode 4

Es gibt zwei Ereignisse, die beim ändern oder Löschen von Daten ausgelöst werden: Bei Geändert und Beim Löschen. Das Ereignis, das als Erstes ausgelöst wird, muss die Transaktion starten. Damit bei mehreren änderungen am Datenbestand nicht jedes Mal eine neue Transaktion gestartet wird, fragt die jeweilige Ereignisprozedur nach, ob schon eine Transaktion gestartet wurde. Für diesen Zweck legen Sie eine Variable namens bolDirty im Kopf des Moduls an:

Dim bolDirty As Boolean

Mit dieser Variable im Gepäck können Sie direkt die Prozeduren anlegen, die durch die Ereigniseigenschaften Bei Geändert und Beim Löschen ausgelöst werden (s. Quellcode 2). Die Prozeduren prüfen, ob die Variable bolDirty den Wert False hat, und starten in diesem Fall eine Transaktion.

Schließlich legen Sie für die Schaltflächen cmdOK und cmdAbbrechen noch zwei Prozeduren an, die prüfen, ob eine Transaktion begonnen wurde, und diese gegebenenfalls beenden oder abbrechen.

Die OK-Schaltfläche löst die Prozedur aus Quellcode 3 aus. Da der Benutzer diese Schaltfläche möglicherweise anklickt, obwohl der aktuelle Datensatz zwar bearbeitet, aber noch nicht gespeichert ist, speichert die Prozedur den Datensatz zunächst. Anschließend prüft die Prozedur den Wert der Variablen bolDirty und damit, ob eine änderung durchgeführt und eine Transaktion ausgelöst wurde. Ist das der Fall, wird das Speichern der innerhalb der Transaktion durchgeführten änderungen ausgelöst.

Die Abbrechen-Schaltfläche soll alle änderungen, die seit dem öffnen des Formulars durchgeführt wurden, rückgängig machen.

Dies ist nur nötig, wenn entweder änderungen gespeichert wurden oder dies nicht der Fall ist und es offene änderungen gibt. In beiden Fällen sorgt die Rollback-Methode für das Verwerfen der vorgenommenen änderungen (s. Quellcode 4).

Probieren Sie das Formular nun aus. Wenn Sie etwa den Namen eines Kunden ändern und anschließend auf OK klicken, wird diese änderung gespeichert und beim nächsten öffnen wieder angezeigt. Klicken Sie auf Abbrechen und öffnen das Formular erneut, finden Sie den Datensatz unverändert vor.

Interessant wird es aber erst bei mehreren änderungen: Löschen Sie einen Datensatz, fügen Sie einen neuen hinzu und ändern Sie vorhandene Datensätze – mit einem Klick auf die Abbrechen-Schaltfläche und dem erneuten öffnen des Formulars finden Sie den alten Stand wieder vor.

Genauso nützlich wie das Verwerfen von änderungen mehrerer Datensätze in einem Formular ohne Unterformular ist die Vorgehensweise in Formularen mit Unterformular. Dabei kommt größtenteils die bereits beschriebene Technik zum Zuge, allerdings lässt sich die Lösung nur auf einen einzelnen Datensatz im Hauptformular und die verknüpften Datensätze im Unterformular ausführen.

Der Grund ist, dass wie bei dem vorherigen Beispiel eine Transaktion nur Datenbankoperationen innerhalb des angegebenen – in diesem Fall des aktuellen – Workspace berücksichtigen kann. Wie beim Hauptformular klappt dies auch in Unterformularen nur, wenn die Datenherkunft mittels Recordset-Objekt zugewiesen wird. Die Zuweisung muss bei jedem Datensatzwechsel im Hauptformular erneut durchgeführt werden.

Leider lässt sich der Recordset-Eigenschaft kein entsprechendes Objekt zuweisen, während eine Transaktion läuft. Daher müssen Sie auf den kompletten Komfort – also änderungen in mehreren Hauptformulardatensätzen plus den im Unterformular angezeigten Daten rückgängig zu machen – leider verzichten und mit dem Verwerfen der änderungen des aktuellen Datensatzes im Hauptformular und der verknüpften Daten im Unterformular vorlieb nehmen.

In einem Formular wie dem Bestellformular aus Bild 1 könnten Sie also nach Lust und Laune änderungen vornehmen und bestellte Artikel hinzufügen und wieder entfernen – nach einem Klick auf eine (hier nicht vorhandene) Abbrechen-Schaltfläche wäre alles wieder beim Alten.

Voraussetzungen

Für die Funktion der nachfolgend beschriebenen Technik müssen einige Voraussetzungen erfüllt sein:

  • Haupt- und Unterformular sind nicht gebunden, die Steuerelemente enthalten aber als Steuerelementinhalt die Felder der später hinzugefügten Datenherkunft.
  • Die Anzeige der Bestätigungen von Datensatzänderungen ist aktiviert (Dialog Optionen, Registerblatt Bearbeiten/Suchen). Sonst wird das Ereignis Nach Löschbestätigung nicht ausgelöst, ohne die die Lösung nicht funktioniert.
  • Aufbau der Formulare

    Das Hauptformular ist genauso wie das Formular aus dem vorherigen Beispiel aufgebaut. Erstellen Sie es zu Beispielzwecken neu oder kopieren Sie das vorhandene Formular und entfernen Sie den enthaltenen Code.

    Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

    den kompletten Artikel im PDF-Format mit Beispieldatenbank

    diesen und alle anderen Artikel mit dem Jahresabo

    Schreibe einen Kommentar