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.