Autor: Christoph Spielmann, Düsseldorf
!
Was Access von anderen Entwicklungsumgebungen unterscheidet, ist insbesondere die einfache und schnelle Entwicklung kompletter Anwendungen ohne viel Programmcode. Eine einfache Datenbank ist so in vielen Fällen bereits nach wenigen Stunden in den Grundzügen fertig gestellt. Sobald die Datenbank aber wächst, werden die ersten Schwächen und Probleme deutlich. Dieser Artikel zeigt Ihnen anhand eines Beispiels für Access 2000, wie Sie diese Schwächen vermeiden.
Der typische Aufbau einer Access-Anwendung sieht folgendermaßen aus: Sie haben verschiedene Tabellen, die – teils mit oder teils ohne Abfragen – an Formulare gebunden sind.
Innerhalb der Formulare werden die Daten angezeigt, verändert und neu hinzugefügt. Beim Verändern und Hinzufügen prüft ein Makro oder eine VBA-Prozedur, ob die Eingaben bestimmten Plausibilitätsregeln entsprechen.
Teilweise wird hierzu auf Werte anderer Formulare zugegriffen und teilweise findet eine Validierung auch innerhalb der Gültigkeitsregel-Eigenschaft von Tabellen oder Formularfeldern statt.
Wenn Ihre Datenbank ein zweites Formular enthält, in dem Sie die gleichen Daten evtl. tabellarisch bearbeiten, dann bringen Sie hier einen Großteil der Logik nochmals unter. Bei änderungen passen Sie dann notwendigerweise beide Formulare an.
Diese Art der Anwendungsentwicklung funktioniert bis zu einem bestimmten Punkt sehr gut, da Ergebnisse relativ zügig erzielt werden können.
Wächst die Datenbank aber weiter, zeigen sich sehr schnell die Schwächen:
Eine solche Software-Architektur wird als monolithisch bezeichnet, da sich alle Funktionen durcheinander in einem Klotz befinden.
Die Lösung des Problems besteht darin, die Anwendung nach dem Schichtenmodell aufzubauen. Hierbei werden häufig drei Schichten verwendet: Datenschicht, Business-Schicht und Präsentationsschicht.
In der Datenschicht sind Funktionen untergebracht, die lesend oder schreibend auf die Tabellen zugreifen. Jeglicher Datenzugriff muss über diese Schicht erfolgen.
In der Business-Schicht werden Plausibilitäten geprüft. Dazu gehört beispielsweise die Prüfung, ob der aktuelle Benutzer die betreffende Funktion ausführen darf oder ob alle Datenfelder korrekte Werte beinhalten. Die Business-Schicht greift zur Prüfung ausschließlich auf die Datenschicht zu.
An oberster Stelle liegt die Präsentationsschicht. Hier werden Daten erfasst oder angezeigt. Die Präsentationsschicht darf nur auf die Business-Schicht, nicht jedoch auf die Datenschicht zugreifen.
Die Vorteile liegen auf der Hand: Wenn Sie in der Business-Schicht eine Prüfung eines Schreibvorgangs unterbringen und alle Formulare dieses Funktion nutzen, brauchen Sie auch nur eine zentrale Funktion anpassen bzw. korrigieren.
Ein anderer Vorteil besteht darin, dass Sie beim Umstieg z. B. auf den SQL-Server lediglich die Datenschicht anpassen müssen. Die Business-Schicht, in der das eigentliche Know-how Ihrer Anwendung liegt, kann dagegen unverändert bleiben.
Das hier vorgestellte Beispiel besteht aus nur einer einzelnen Tabelle, die Adressdaten zusammen mit einem Anlage- und einem änderungsdatum speichert.
Die Beispieldatenbank finden Sie auf der Heft-CD unter dem Dateinamen Klassen2000.mdb.
Die Tabelle tblAdressen besteht aus den folgenden Feldern (siehe Bild 1):
Bild 1: Die Tabelle tblAdressen in der Entwurfsansicht.
Standardwerte oder Gültigkeitsregeln sind nicht definiert, da diese Aufgaben von der Business-Schicht erledigt werden.
Hinweis
Parallel zu der Beispieldatenbank Klassen2000.mdb finden Sie noch eine weitere Datenbank namens KlassenXP.mdb, die die Vorgehensweise beim Einsatz von XP beschreibt. Access 2000 enthält einige Fehler die bei der Bindung von Recordsets an Formulare zutage treten. Bei Access XP sind diese Probleme behoben, sodass hier einige Prozeduren einen einfacheren und eleganteren Aufbau haben.
Zum Zugriff auf die Tabellen ist nun zunächst einmal die Anlage der Datenschicht erforderlich.
Um eine gute übersicht zu gewährleisten, sollte pro Tabelle ein entsprechendes Klassenmodul angelegt werden, in dem alle Funktionen untergebracht sind, die sich mit dieser Tabelle beschäftigen.
Public Function GetAdresse(AdresseID As Long) _ As Recordset Dim SQL As String Dim Data As New ADODB.Recordset SQL = "SELECT * FROM tblAdressen" SQL = SQL & " WHERE AdresseID=" & CStr(AdresseID) With Data .ActiveConnection = CurrentProject.Connection .Source = SQL .LockType = adLockReadOnly .CursorType = adOpenStatic .CursorLocation = adUseClient .Open End With Set GetAdresse = Data End Function
Quellcode 1
Bild 2: Der Zugriff auf die Tabellen erfolgt ausschließlich über das Klassenmodul AdressenD.
Da in diesem Beispiel nur eine Tabelle zum Einsatz kommt, existiert auch nur ein Klassenmodul. Dies trägt den Namen AdressenD. Das D steht hierbei für Datenschicht (siehe Bild 2).
Einzelne Adresse abrufen
Die erste Prozedur dieses Klassenmoduls trägt den Namen GetAdresse. Ihre Aufgabe ist es, eine einzelne Adresse aus der Tabelle abzurufen und die Daten in Form eines Recordsets zurück zu liefern. Als Parameter erwartet die Prozedur die Primärschlüsselnummer der Adresse (s. Quell-code 1).
Innerhalb der Prozedur wird ein SQL-Text zusammengestellt mit dessen Hilfe danach ein Recordset gefüllt wird. Dieses wird dann als Ergebnis der Funktion zurückgegeben. Damit sich änderungen am Recordset, die in einer höheren Schicht durchgeführt werden, nicht auf die Datenbank auswirken, sollte das Recordset vor der übergabe an die höhere Schicht noch entbunden (disconnected) werden:
Set .ActiveConnection = Nothing
Schließlich sollen Schreibzugriffe kontrolliert über eine andere Datenschicht-Funktion durchgeführt werden.
Aufgrund eines Fehlers in Access 2000 lässt sich ein solches Recordset jedoch nicht an ein Formular binden, weshalb auf diese Anweisung in dieser Beispieldatenbank generell verzichtet werden muss. Beim Einsatz von Access XP tritt das Problem allerdings nicht mehr auf.
Um direkte Schreibzugriffe zu verhindern, wird die LockType-Eigenschaft auf ReadOnly gestellt.
Der LockType wird bewusst nicht auf ReadOnly gesetzt. Dies hat den folgenden Grund:
Public Function GetAdressenSuchergebnis(Firmenname As _ String, Nachname As String) As Recordset Dim SQL As String SQL = "SELECT AdresseID, Firmenname, Nachname, " _ SQL = SQL & "Vorname, PLZ FROM tblAdressen" SQL = SQL + " WHERE True" If Firmenname <> "" Then SQL = SQL + " AND Firmenname LIKE " + _ Quote("%" + Firmenname + "%") End If If Nachname <> "" Then SQL = SQL + " AND Nachname LIKE " + _ Quote("%" + Nachname + "%") End If Dim Data As New ADODB.Recordset With Data .ActiveConnection = CurrentProject.Connection .Source = SQL .LockType = adLockReadOnly .CursorType = adOpenStatic .CursorLocation = adUseClient .Open End With Set GetAdressenSuchergebnis = Data End Function
Quellcode 2
Public Function SaveAdresse(Firmenname As String, _ Nachname As String, Vorname As String, _ Strasse As String, PLZ As String, Ort As String, _ Anlagedatum As Date, änderungsdatum As Date) As Long Dim SQL As String SQL = "SELECT * FROM tblAdressen WHERE False" Dim Data As New ADODB.Recordset With Data .ActiveConnection = CurrentProject.Connection .Source = SQL .LockType = adLockOptimistic .CursorType = adOpenDynamic .MaxRecords = 1 .Open .AddNew !Firmenname = ZN(Firmenname) !Nachname = ZN(Nachname) !Vorname = ZN(Vorname) !Strasse = ZN(Strasse)
Quellcode 3 (Fortsetzung nächste Seite)
Das Recordset wird später auch in der Präsentationsschicht verwendet und hier an das entsprechende Access-Formular gebunden.
Wäre hier ReadOnly eingestellt, könnte man die Daten des Formulars nicht bearbeiten (und dann letztendlich auch nicht an die entsprechende Speicher-Funktion weiterleiten).
Abfragen eines Suchergebnisses