Zur Hauptseite ... Zum Onlinearchiv ... Zum Abonnement ... Zum Newsletter ... Zu den Tools ... Zum Impressum ... Zum Login ...

Gedrucktes Heft

Diesen Beitrag finden Sie in Ausgabe 3/2010.

Unser Angebot für Sie!

Lesen Sie diesen Beitrag und 500 andere sofort im Onlinearchiv, und erhalten Sie alle zwei Monate brandheißes Access-Know-how auf 72 gedruckten Seiten! Plus attraktive Präsente, zum Beispiel das bald erscheinende Buch 'Access 2010 - Das Grundlagenbuch für Entwickler'!

Diesen Beitrag twittern

Zusammenfassung

Lernen Sie eine Klasse kennen, die Ihnen das Schreiben einer Änderungshistorie für ein Formular abnimmt.

Techniken

Formulare, Tabellen

Voraussetzungen

Access 2000 und höher

Beispieldateien

AenderungsprotokollierungII.mdb

Shortlink

www.access-im-unternehmen.de/719

Änderungsprotokoll mit Klasse

André Minhorst, Duisburg

Im Beitrag Änderungsdaten protokollieren (www.access-im-unternehmen.de/672) haben wir Techniken vorgestellt, welche die Verwaltung einer Änderungshistorie stark erleichtert. Im vorliegenden Beitrag gehen wir noch weiter und vereinfachen die Geschichtsschreibung für Formulare. Dazu brauchen Sie dem Formular nur noch eine Klasse zuzuweisen - den Rest übernimmt unsere kleine Erweiterung.

Stellen Sie sich vor, Sie wollten die Änderungen an den Datensätzen eines Formulars beim Anlegen und Löschen sowie bei der zuletzt erfolgten Änderung in den entsprechenden Feldern der Tabelle speichern und bräuchten dazu nur ein paar immer gleiche Codezeilen im Formular unterzubringen.

Nicht möglich? Aber sicher - Sie brauchen nur zuvor die Datenherkunft mit den Feldern zum Speichern der Historie-Daten auszustatten. Und wie das geht, haben Sie ja bereits im oben bereits erwähnten Beitrag Änderungsdaten protokollieren erfahren.

Sie brauchen nur eine Tabelle, die mit den Zusatzfeldern wie in Abb. 1 ausgestattet ist, eine Abfrage, die alle Datensätze daraus liefert außer solche, die als gelöscht markiert sind (s. Abb. 2) und ein Formular, das die Abfrage als Datenherkunft verwendet und unsere Klasse clsAenderungsprotokollierung einsetzt.

pic001.png

Abb. 1: Die Tabelle mit Historie-Feldern

pic002.png

Abb. 2: Diese Abfrage liefert alle nicht gelöschten Datensätze der obigen Tabelle

Um diese Klasse zu verwenden, erstellen Sie zunächst eine Objektvariable im Kopf des Klassenmoduls des Formulars (falls dieses noch nicht vorhanden ist: Eigenschaft Enthält Modul auf Ja einstellen und auf den Ribbon-Eintrag Entwurf|Tools|Code anzeigen klicken):

Dim objAenderungsprotokollierung As clsAenderungsprotokollierung

Danach fügen Sie der Eigenschaft Beim Laden den Wert [Ereignisprozedur] hinzu, klicken auf die Schaltfläche neben der Eigenschaft und ergänzen die noch leere Prozedur Form_Load wie folgt:

Private Sub Form_Load()

    Set objAenderungsprotokollierung = _

    New clsAenderungsprotokollierung

    With objAenderungsprotokollierung

        Set .Form = Me

        .BenutzerID = GetCurrentUser

    End With

End Sub

Diese Prozedur erzeugt ein neues Objekt auf Basis der Klasse clsAenderungsprotokollierung und weist seiner Eigenschaften einige Werte zu. Die Eigenschaft Form wird mit einem Verweis auf das aktuelle Formular versehen, und die Eigenschaft BenutzerID füllen wir mit dem Wert der Funktion GetCurrentUser. Diese Funktion ist hier noch ein Dummy, den Sie abhängig von der in Ihrer Anwendung eingesetzten Benutzerverwaltung noch anpassen müssen:

Public Function GetCurrentUser() As Long

    GetCurrentUser = 1

End Function

Der Dummy liefert schlicht den Wert 1 als ID des aktuellen Benutzers (später greifen Sie mit dieser Funktion beispielsweise auf eine Optionen-Tabelle zu, welche die ID des aktuellen Benutzers speichert).

Die Klasse clsAenderungsprotokollierung

Kommen wir zum Arbeitstier der Beispieldatenbank - der Klasse clsAenderungsprotokollierung. Diese deklariert zunächst die folgenden Variablen:

Private WithEvents m_Form As Form

Private m_BenutzerID As Variant

Private bolDelete As Boolean

Private lngTimerIntervalOld As Long

m_Form bekommt über die öffentliche Set-Prozedur Form einen Verweis auf das aufrufende Formular zugewiesen.

Sie ist deshalb mit dem Schlüsselwort WithEvents deklariert worden, damit sie auf die Ereignisse des aufrufenden Formulars reagieren kann. Dazu sind drei Bedingungen zu erfüllen:

  • Das aufrufende Formular besitzt ein Klassenmodul, was sicher der Fall ist, weil darin ja die Klasse clsAenderungsprotokollierung instanziert wird.
  • Wir weisen der entsprechenden Ereigniseigenschaft des Objekts m_Form den Wert [Event Procedure] zu.
  • Wir legen eine entsprechende Ereignisprozedur im Klassenmodul an.

Die Property Set-Prozedur weist den Formularverweis zu und stellt die Ereigniseigenschaften ein:

Public Property Set Form(frm As Form)

    Set m_Form = frm

    With m_Form

        .BeforeUpdate = "[Event Procedure]"

        .AfterUpdate = "[Event Procedure]"

        .OnDelete = "[Event Procedure]"

        .OnTimer = "[Event Procedure]"

    End With

End Property

Bevor uns wir um die passenden Ereignisprozeduren kümmern, schauen wir uns noch kurz die Property Let-Prozedur zum Erfassen des aktuellen Benutzers an:

Public Property Let BenutzerID(varBenutzerID As Variant)

    m_BenutzerID = varBenutzerID

End Property

Diese speichert die ID des Benutzers schlicht in der Member-Variablen m_BenutzerID. Sollten Sie diese Lösung für eine Benutzertabelle verwenden, die ein Textfeld als Primärschlüsselfeld einsetzt, müssen Sie den Datentyp und den späteren Zugriff auf das Feld entsprechend anpassen.

Ausgeklammerte Formularereignisse

Die nachfolgend beschriebenen Ereignisprozeduren werden, wenn die Klasse ordnungsgemäß instanziert und ihre Variable m_Form mit einem Verweis auf das Formular versehen wurde, genau wie die Ereignisse im Klassenmodul des Formulars selbst ausgelöst.

Die Ereignisprozeduren haben wir gegebenüber dem oben genannten Beitrag ein wenig angepasst.

Beim Löschen eines Datensatzes wird als erstes das Ereignis Beim Löschen ausgelöst:

Private Sub m_Form_Delete(Cancel As Integer)

    m_Form!GeloeschtAm = Now

    bolDelete = True

    lngPosition = m_Form.Recordset.AbsolutePosition

    m_Form.Dirty = False

    Cancel = True

End Sub

Diese stellt zunächst das Löschdatum ein - allerdings nur, damit der Datensatz eine Änderung erfährt und die beiden Prozeduren Vor Aktualisiserung und Nach Aktualisierung im Anschluss ausgelöst werden.

Dann stellt Sie die Variable bolDelete auf True ein. Dadurch erfahren die nachfolgenden Prozeduren, ob hier nur ein einfaches Editieren oder ein Löschvorgang stattfindet.

Das ist nötig, weil das eigentliche Löschen mit Cancel = True später abgebrochen wird (wir wollen den Datensatz ja gar nicht löschen, sondern diesen nur als gelöscht markieren).

Zwischendurch merken wir uns in lngPositon die aktuelle Position des Datensatzzeigers und speichern den Datensatz mit m_Form. Dirty = False.

Aus dem Löschvorgang haben wir nun einen normalen Änderungsvorgang gemacht, der in den nachfolgend ausgelösten Ereignisprozeduren jedoch noch eine kleine Änderung nach sich zieht.

In der durch die Datensatzänderung ausgelösten Ereignisprozedur Vor Aktualisierung prüfen wir zunächst, ob wir es mit einen neuen Datensatz zu tun haben und stellen dementsprechend die Anlagefelder der Tabelle ein (s. Abb. 3).

pic003.png

Abb. 3: Formular mit Anlage- und Änderungsdatum

Falls nicht, gab es entweder einen Lösch- oder einen Änderungsvorgang, wobei der Wert der Variablen bolDelete den Unterschied ausmacht. Diese hätte bei einem Löschvorgang zuvor den Wert True erhalten. Der Unterschied zwischen beiden Aktionen beschränkt sich auf die Felder des Datensatzes, die nun mit Änderungs- beziehungsweise Löschdaten gefüllt werden.

Private Sub m_Form_BeforeUpdate(Cancel As Integer)

    If m_Form.NewRecord = True Then

        m_Form!AngelegtAm = Now

        m_Form!AngelegtDurch = m_BenutzerID

    Else

        If bolDelete = False Then

            m_Form!ZuletztGeaendertAm = Now

            m_Form!ZuletztGeaendertDurch =

            m_BenutzerID

        Else

            m_Form!GeloeschtAm = Now

            m_Form!GeloeschtDurch = m_BenutzerID

        End If

    End If

End Sub

Für frisch angelegte und geänderte Datensätze ist die Arbeit bezüglich der Änderungshistorie bereits erledigt, beim Löschen eines Datensatzes noch nicht ganz.

Hier interessiert zunächst der Inhalt der Ereignisprozedur Nach Aktualisierung:

Private Sub m_Form_AfterUpdate()

    If bolDelete Then

        lngTimerIntervalOld = m_Form.TimerInterval

        m_Form.TimerInterval = 100

    End If

End Sub

Darin wird die Variable bolDelete erneut geprüft,. Wenn Sie den Wert True aufweist, stellt die Prozedur die Eigenschaft TimerIntervall auf den Wert 100 ein, damit die mit der Klasse mitgelieferte Ereignisprozedur m_Form_Timer kurz danach ausgelöst wird.

Allerdings speichert sie den vorher den aktuellen Wert dieser Eigenschaft, um ihn anschließend wiederherzustellen.

Die durch den Timer ausgelöste Ereignisprozedur sieht schließlich wie folgt aus:

Private Sub m_Form_Timer()

    m_Form.TimerInterval = lngTimerIntervalOld

    If bolDelete Then

        m_Form.Requery

        If lngPosition > 0 Then

            m_Form.Recordset.AbsolutePosition =

            lngPosition - 1

        End If

    End If

    bolDelete = False

End Sub

Sie stellt zunächst die Eigenschaft TimerInterval wieder auf den alten Wert ein. Hat bolDelete den Wert True, aktualisiert sie die Datenherkunft des Formulars mit der Requery-Methode.

Dadurch springt der Datensatzzeiger eigentlich zum ersten Datensatz der Datenherkunft. Für den Benutzer ist es aber vermutlich angenehmer, wenn der Datensatz markiert wird, der sich direkt vor dem gelöschten Datensatz befindet.

Und dafür haben wir die Position des Datensatzzeigers in der Variablen lngPostion gespeichert: Wir stellen die Positon nach dem Löschen des Datensatzes einfach auf die Position gleich vor diesem Datensatz ein.

Warnhinweis

Wenn Sie diese Klasse einsetzen, sollten Sie diese gründlich prüfen. Sollte während der Arbeit mit dem damit ausgestatteten Formular nämlich ein unbehandelter Fehler auftauchen, wird die Objektvariable objAenderungsprotokollierung einfach geleert.

Die darin enthaltenen Ereignisse werden somit nicht mehr ausgelöst - auch nicht beim Löschen! Das bedeutet, dass das Löschen eines Datensatzes durch den Benutzer nicht nur zum Markieren des Datensatzes als »gelöscht« führt, sondern das der Datensatz tatsächlich gelöscht wird.

Um dies auszuprobieren, legen Sie einfach eine Schaltfläche mit der folgenden Prozedur im Formular an:

Private Sub cmdFehlerAusloesen_Click()

    Debug.Print 1 / 0

End Sub

Wenn Sie nach Auftreten dieses Fehlers einen Datensatz löschen, wird dieser komplett gelöscht.

Auch wenn Sie im Formular bereits einen Timer verwenden, könnte es zu Irritationen kommen: Die Klasse clsAenderungsprotokollierung stellt das Timer-Intervall nach seiner Änderung zwar wieder auf den ursprünglichen Wert zurück, aber das Ereignis Bei Zeitgeber wird natürlich nicht nur das OnTimer-Ereignis der Klasse, sondern auch ein eventuell im Formular enthaltenes ausgelöst. Solche Interferenzen sollten Sie ebenfalls ausgiebig testen.

Kompletten Artikel lesen?

Einfach für den Newsletter anmelden, dann lesen Sie schon in einer Minute den kompletten Artikel und erhalten die Beispieldatenbanken.

E-Mail:

Download

Download

Die .zip-Datei enthält folgende Dateien:

AenderungshistorieII.mdb

Beispieldateien downloaden

© 2003-2015 André Minhorst Alle Rechte vorbehalten.