André Minhorst, Duisburg, und Dr. Holger H. Stutzke, Bremen
Viele Anwendungen verlangen eine konsistente Historie aller änderungen im Datenbestand. Access bietet dazu keine perfekten Möglichkeiten, aber mit ein wenig Eigeninitiative seitens des Entwicklers ist die lückenlose Historie dennoch leicht realisierbar. Je nachdem, ob die Historie wirklich lückenlos sein muss oder ob Informationen wie Anlege-, änderungs- und Löschdaten der einzelnen Datensätze ausreichen, gibt es zwei Varianten für die Pflege einer Historie.
Bei diversen Anwendungsfällen wird eine konsistente Speicherung aller Daten und Datenänderungen in einer Datenbank erwartet.
Dabei kann es sich um sicherheits- oder finanztechnisch relevante Anwendungen handeln, bei denen eine lückenlose Historie sogar Pflicht ist, oder man möchte aus anderen Gründen genau wissen, zu welchem Zeitpunkt welcher Datenbestand Gültigkeit hatte. Wieder andere Anwendungen erfordern nur rudimentäre Informationen über die änderung von Daten wie das jeweilige Datum und den durchführenden Benutzer beim Erstellen, letzten ändern oder Löschen eines Datensatzes.
Beide Methoden erfordern, dass die gewünschten Daten beim Erstellen, ändern oder Löschen von Informationen gespeichert werden, und das natürlich automatisch.
Access bietet dazu keine speziellen Mittel, sodass die benötigten Aktionen unmittelbar bei der Dateneingabe, also im entsprechenden Formular, vorgenommen werden müssen. Da die Speicherung automatisch erfolgen soll, verwendet man am besten die Ereignisprozeduren, die unmittelbar vor beziehungsweise nach der änderung der Daten ausgelöst werden.
Client-Server-Systeme wie Microsoft SQL Server, dessen abgespeckte Version MSDE und andere bieten für solche änderungsdaten so genannte Trigger an, die automatisch beim Anlegen, ändern oder Löschen von Datensätzen ausgelöst werden und die Werte der Tabellenfelder vor und nach der änderung bereitstellen.
Da Access diese Vorzüge nicht bietet, lernen Sie im vorliegenden Beitrag, wie Sie eine formulargesteuerte Funktionalität zur Pflege einer änderungshistorie erstellen.
Sie können natürlich nur eine änderungshistorie zu Datensätzen führen, die auch vorhanden sind. Sie müssen sich also an dieser Stelle entscheiden, ob mit einem gelöschten Datensatz auch die Historie des Datensatzes gelöscht werden soll. Lautet die Antwort ja, haben Sie sich definitiv für die einfacher zu realisierende Variante entschieden.
Leider sehen die Anforderungen sicherheits- oder finanztechnisch kritischer Anwendungen den anderen Fall vor. Das bedeutet, dass Sie auch gelöschte Datensätze nicht so einfach entfernen dürfen. Und damit stellt sich erneut eine wichtige Frage: Möchten Sie die gelöschten Daten mit einem entsprechenden Flag versehen und alle Abfragen und Datenherkünfte so anpassen, dass nur als nicht gelöscht gekennzeichnete Datensätze angezeigt werden, oder möchten Sie die Datensätze tatsächlich aus der Ursprungstabelle löschen, im gleichen Schritt aber in einer weiteren Tabelle gleichen Aufbaus archivieren
Die Auflistung der Techniken und der Vor- und Nachteile der beiden Varianten könnte wahrscheinlich einen eigenen Beitrag füllen. An dieser Stelle wird davon ausgegangen, dass Performance und Speicherplatz Sie nicht daran hindern, gelöschte Daten durch das Setzen eines Flags als solche zu markieren und sie nicht zu löschen oder zu verschieben.
Wenn änderungen unter Angabe des Ausführenden gespeichert werden sollen, müssen Sie dessen Identität ermitteln. Das können Sie auf unterschiedliche Arten erledigen. Die richtige Auswahl hängt unter anderem davon ab, ob die Datenbank das Sicherheitssystem von Access verwendet. Falls ja, können Sie einfach den Namen des aktuellen Benutzers eintragen. Den Namen können Sie mit folgender Funktion ermitteln:
=CurrentUser()
Falls nein, können Sie beispielsweise den Namen des aktuell auf dem Rechner eingeloggten Benutzers verwenden – Beispiele für die Ermittlung dieses Benutzers finden Sie im Modul mdlBenutzerinformationen der Beispieldatenbank.
Die einfache änderungshistorie dient einfach nur der Protokollierung des Benutzers und des Datums für das Anlegen, die letzte änderung und für das Löschen eines Datensatzes. Sie erfordert folgende Maßnahmen:
Hinweis
Die Beschreibung der Maßnahmen erfolgt anhand der Tabellen Artikel, Kategorie und Lieferanten sowie des Formulars Artikel, die Sie zum Nachvollziehen der nachfolgenden Schritte am besten aus der Nordwind-Datenbank in eine neue, leere Datenbank importieren. Sie finden die fertigen Beispiele allerdings auch auf der Heft-CD. Die Dateien heißen Historie97.mdb (für Access 97) und Historie00.mdb (für Access 2000 und höher).
Vorbereiten der Tabelle
Damit Sie die änderungsdaten in der Tabelle speichern können, müssen Sie den Entwurf entsprechend anpassen. Dazu legen Sie die folgenden Felder neu an:
Anpassen des Formulars
Nun passen Sie das Formular so an, dass bei jeder änderung an einem Datensatz eine entsprechende Protokollierung erfolgt.
Das bedeutet, dass Sie drei unterschiedliche Aktionen berücksichtigen müssen: das Anlegen neuer Datensätze und das ändern und Löschen bestehender Datensätze.
Private Sub Form_BeforeInsert(Cancel As Integer) Me!AngelegtAm = Date Me!AngelegtDurch = CurrentUser End Sub
Quellcode 1
Private Sub Form_BeforeUpdate(Cancel As Integer) Me!GeaendertAm = Date Me!GeaendertDurch = CurrentUser End Sub
Quellcode 2
Private Sub Form_BeforeUpdate(Cancel As Integer) If Me.NewRecord Then Me!AngelegtAm = Date Me!AngelegtDurch = CurrentUser Else Me!GeaendertAm = Date Me!GeaendertDurch = CurrentUser End If End Sub
Quellcode 3
Hinweis
Die nachfolgende Beschreibung bezieht sich auf das Formular Artikel der Nordwinddatenbank.
Anlegen von Datensätzen
Das Anlegen eines Datensatzes löst das Ereignis Vor Eingabe aus. Das Speichern dieses neuen Datensatzes löst das Ereignis Nach Eingabe aus. Das erstgenannte Ereignis ist für das Anlegen der änderungsdaten interessant. Legen Sie für diese Ereigniseigenschaft die Prozedur aus Quellcode 1 an.
Wenn Sie nun einen neuen Datensatz anlegen, weist die Prozedur den beiden Feldern AngelegtAm und AngelegtDurch die Werte der Funktionen Date und CurrentUser zu.
ändern von Datensätzen
Eine Datensatzänderung liegt immer vor, wenn mindestens ein Feld des Datensatzes geändert wurde. Das Ereignis, das beim Speichern eines geänderten Datensatzes ausgelöst wird, heißt Vor Aktualisierung. Unmittelbar nach dem Speichern wird noch das Ereignis Nach Aktualisierung ausgelöst – soweit der Speichervorgang nicht in der Ereignisprozedur für das Ereignis Vor Aktualisierung abgebrochen wird oder ein Fehler auftritt. Mit der Ereignisprozedur aus Quellcode 2 legen Sie die änderungsdaten an.
Die Prozedur belegt die beiden Felder GeaendertAm und GeaendertDurch mit den entsprechenden Werten. Direkt im Anschluss wird die neue Version des Datensatzes gespeichert.
Anlegen und ändern in einem Schritt
Zu beachten ist, dass auch das Neuanlegen eines Datensatzes diese beiden Prozeduren auslöst. Damit würden beim Neuanlegen sowohl die Felder für das Neuanlegen als auch für das ändern eines Datensatzes aktualisiert.
Wenn die Felder GeaendertAm und GeaendertDurch beim Neuanlegen eines Datensatzes nicht geändert werden sollen, verwenden Sie die Prozedur aus Quellcode 3 für das Ereignis Vor Aktualisierung.
Die Prozedur überprüft, ob es sich bei dem Datensatz um einen neuen Datensatz handelt, und ändert die entsprechenden Felder.
Löschen vonDatensätzen
Das Löschen eines Datensatzes löst das Ereignis Beim Löschen aus. Da das Löschen eines Datensatzes auch automatisch die Historie mitlöschen würde, sollen lediglich die beiden Felder GeloeschtDurch und GeloeschtAm aktualisiert und der eigentliche Löschvorgang abgebrochen werden.
Zusätzlich müssen Sie natürlich die Datenherkunft des Formulars so anpassen, dass Datensätze, die einen Wert für eines der Felder GeloeschtAm oder GeloeschtDurch enthalten, nicht mehr angezeigt werden. Daher ändern Sie die Eigenschaft Datenherkunft auf den folgenden Wert:
Private Sub Form_Delete(Cancel As Integer) Geloescht = True End Sub Private Sub Form_BeforeDelConfirm(Cancel As Integer, Response As Integer) Cancel = True End Sub Private Sub Form_AfterDelConfirm(Status As Integer) Me!GeloeschtAm = Date Me!GeloeschtDurch = CurrentUser Me.Requery End Sub
Quellcode 4
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