Datenzugriff im Schichtbetrieb

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:

  • änderungen müssen häufig an vielen Stellen parallel durchgeführt werden.
  • Wenn man an einer Stelle eine Kleinigkeit ändert, wirkt sich dies oft auf viele andere Stellen der Datenbank aus. Die Folge sind viele Fehler und eine wenig robuste Datenbank.
  • Da die Geschäftslogik über viele Makros, Module, Abfragen und Formulare verstreut ist, ist die Pflege zeitintensiv. Zudem können fremde Entwickler nur sehr schwer die Funktionsweise der Datenbank nachvollziehen.
  • Der Entwickler kann leicht die übersicht über die Software verlieren, sodass sich weitere Fehler einschleichen.
  • 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 (s. Abb. 1):

  • AdresseID (Long Integer, Primärschlüssel der Tabelle)
  • Firmenname (Text)
  • Nachname (Text)
  • Vorname (Text)
  • Straße (Text)
  • PLZ (Text)
  • Ort (Text)
  • Anlagedatum (Datum/Uhrzeit)
  • änderungsdatum (Datum/Uhrzeit)
  • Abb. 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

    Abb. 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 (s. Abb. 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

    Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
    Hier geht es zur Bestellung des Jahresabonnements des Magazins Access im Unternehmen:
    Zur Bestellung ...
    Danach greifen Sie sofort auf alle rund 1.000 Artikel unseres Angebots zu - auch auf diesen hier!
    Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

    Schreibe einen Kommentar