Disconnected Recordsets

Konfigurationsdaten, Meldungen oder SQL-Befehle kann man in passenden Tabellen speichern und bei Bedarf per DLookup oder DAO auf diese zugreifen. Da diese Daten sich in der Regel nur selten ändern, kann man sie getrost einmal zu Beginn der Session auslesen und dann auf die temporär gespeicherten Daten zugreifen. Das spart Ressourcen und erhöht die Zugriffsgeschwindigkeit – dank ADO und Disconnected Recordsets.

Neue Datenzugriffstechnik mit ADO

Das Schlagwort “Disconnected Recordsets” geisterte durch die Welt der Programmierung, seit Microsoft die Version 2.0 von “ADO” (ActiveX Data Objects) für Datenbanken publiziert hatte. ADO war ursprünglich als Nachfolger für DAO (Data Access Objects) geplant.

Der Datenbankzugriff mit ADO weist gegenüber DAO einige Verbesserungen in der Performance auf, wenn SQL-Server-Backends zum Einsatz kommen. Der Hemmschuh ist in diesem Fall die von DAO für den Zugriff benötigte ODBC-Schnittstelle. Für die Festlegung des Datenbankzugriffs wird ein OLE DB-Provider benötigt – eine der Neuerungen von ADO. Mit Hilfe dieses Providers können Sie dem Connection-Objekt mitteilen, auf welche Datenbank es zugreifen soll und um welche Version es sich dabei handelt. Mit ADO lassen sich nahezu alle gebräuchlichen Datenbanken wie etwa Microsoft Access, SQL-Server, Oracle oder Informix ansprechen.

Die wichtigsten drei Komponenten des ADO-Datenmodells sind folgende:

  • Connection (“Verbindung”): Enthält den Ort und den Namen der angesprochenen Datenbank, braucht für eine angesprochene Datenbank nur einmal definiert zu werden.
  • Recordset (“Datensatz-Objekt”): Der Verbindung untergeordnetes und abhängiges Objekt, das Daten in Form von Tabellen oder Abfragen zurückgibt; ist die Grundlage der folgenden Ausführungen.
  • Command (“Befehls-Objekt”): Das Command-Objekt benötigt keine Connection und dient dem ändern der Datenbank und der enthaltenen Daten mit Befehlen wie UPDATE, CREATE TABLE oder INSERT INTO.

Vergleich des Zugriffs auf Recordsets

Die folgenden Codebeispiele zeigen den Unterschied des Datenzugriffs mit DAO und ADO. Beachten Sie, dass das DAO-Beispiel nicht mit Access-Projekten funktioniert. Das hängt damit zusammen, dass DAO ausschließlich mit der JET-Engine arbeiten kann, egal, ob die Relationen aus einer Access-Datenbank oder einer ODBC-Datenbank stammen.

öffnen eines Recordsets mit DAO

Um mittels DAO ein Recordset zu öffnen, benötigt man nicht viel. Das Codebeispiel aus Listing 1 verwendet die OpenRecordset-Methode zum Erzeugen des Recordsets und liefert dieses als Funktionswert an die aufrufende Routine zurück.

Listing 1: öffnen eines Recordset-Objekts mit DAO

Public Function OpenRecordSet_By_DAO() As DAO.RecordSet
     On Error GoTo ErrorHandler 
     Dim db As DAO.Database
     Dim rst As DAO.Recordset 
     Set db = DBEngine(0)(0)
     Set rst = db.OpenRecordset("tblStammdaten", dbOpenDynaset) 
     If Not rst Is Nothing Then
         Set OpenRecordSet_By_DAO = rst
     End If 
ExitCode:
     On Error Resume Next
     Set rst = Nothing
     Set db = Nothing
     Exit Function 
ErrorHandler:
     MsgBox Err.Description, vbInformation, "OpenRecordSet_By_DAO"
     Resume ExitCode
End Function

öffnen eines Recordsets mittels ADO

Wollen Sie die gleiche Funktion mit ADO nachbilden, müssen Sie ein paar wenige Codezeilen mehr schreiben. Dies ist aber dadurch bedingt, dass ADO wesentlich mehr Möglichkeiten besitzt als DAO. Der Unterschied im Code wird schnell ersichtlich. Der Code für den Zugriff mittels ADO ist zwar etwas länger, dafür aber auch strukturierter (s. Listing 2). Zunächst baut die Routine durch Setzen der Eigenschaft ActiveConnection eine Verbindung zur Datenquelle auf.

Listing 2: öffnen eines Recordset-Objekts mit ADO

Public Function OpenRecordSet_By_ADO() As ADODB.Recordset
     On Error GoTo ErrorHandler
     Dim rst As ADODB.Recordset 
     Set rst = New ADODB.Recordset 
     With rst
         Set .ActiveConnection = CurrentProject.Connection
         .CursorLocation = adUseServer
         .CursorType = adOpenDynamic
         .Source = "tblStammdaten"
         .Open
     End With 
     If Not rst Is Nothing Then
         Set OpenRecordSet_By_ADO = rst
     End If 
ExitCode:
     On Error Resume Next
     Set rst = Nothing
     Exit Function 
ErrorHandler:
     MsgBox Err.Description, vbInformation, "OpenRecordSet_By_ADO"
     Resume ExitCode
End Function

Im nächsten Schritt konfiguriert sie das zu füllende Recordset und öffnet es anschließend mit der Open-Methode. Was bei DAO ein Einzeiler ist, lässt sich auch mit ADO in einer Zeile realisieren, allerdings scheint diese Variante unübersichtlicher – auch im Vergleich mit dem passenden DAO-Aufruf, da ADO mehr Optionen bereitstellt:

rst.Open [Source], 
[ActiveConnection], [CursorType], [LockType], [Options]

Die Eigenschaft ActiveConnection ermöglicht es dem Recordset, eine Verbindung zur Datenbank aufzubauen. Die so genannten Connectionstrings für die gängigsten Datenquellen findet man sowohl im Internet [1] als auch in der Online-Hilfe von Microsoft. Die Codes zu obigem Beispiel finden Sie im Formular Demonstration DAO – ADO der Beispieldatenbank (siehe Bild 1).

pic001.tif

Bild 1: Beispielformular zum Erzeugen eines Recordsets mit DAO und ADO

Was sind
“Disconnected Recordsets”

Ab ADO 2.0 (wurde 1998/1999 im Rahmen der Einführung von MDAC 2.0 ausgeliefert) können Recordsets von ihrer Verbindung getrennt werden. Der Zeiger eines Recordsets auf die von ihm verwendete Datenquelle wird durch die Eigenschaft ActiveConnection repräsentiert. Diese Eigenschaft kann seit der Version 2.0 nicht nur ausgelesen, sondern auch neu gesetzt werden.

Dabei kann sie sowohl auf Nothing als auch auf eine andere Verbindung als die ursprüngliche gesetzt werden. Wenn ein Recordset mit folgender Anweisung von seiner Datenquelle abgekoppelt wird, kann es immer noch bearbeitet werden:

Set .ActiveConnection = Nothing

Voraussetzung hierfür ist jedoch, dass ein Cursor auf der Client-Seite verwendet wird:

.CursorLocation = adUseClient

Außerdem muss die Eigenschaft LockType den Wert adLockBatchOptimistic aufweisen:

.LockType = adLockBatch

Dadurch werden alle Datensätze des Recordsets im Speicher gehalten und auf Seiten der Datenbank keine Sperren gesetzt. Das Recordset führt seine Statusinformationen korrekt mit. Sie können zu einem späteren Zeitpunkt die Verbindung wieder herstellen und mit der Methode UpdateBatch die änderungen wieder in die Datenbank einspielen.

Warum “Disconnected Recordsets”

Die Verwendung von Disconnected Recordsets wird im ersten Augenblick nicht unbedingt einleuchtend sein, insbesondere, wenn man (wie auch ich selbst) bisher immer mit JET-Datenbanken oder zumindest mit sehr leistungsfähigen Datenbank-Backends gearbeitet hat.

Ein klassisches Beispiel für die Verwendung von Disconnected Recordsets bietet das Internet. Stellen Sie sich vor, Sie haben einen gut laufenden Online-Shop. Jede Listbox befüllen Sie mit Daten aus Ihrem Artikelstamm.

Bei jeder Aktualisierung der Seite würden bei einer bestehenden Verbindung des Recordsets zur Datenquelle die Daten erneut aus der Datenbank gelesen werden. Sollte gerade nur ein Käufer in Ihrem Shop einkaufen, wäre diese Performance-Bremse noch zu ertragen – stellen Sie sich aber mal vor, Sie seien der Betreiber von Amazon, EBay, etc.

Es wird schnell klar, wo der Vorteil von Disconnected Recordsets liegt – der Zugriff auf die Datenbank erfolgt einmalig und die Anwendung kann mit den Daten lokal im Arbeitsspeicher des Computers arbeiten. Es erklärt sich von selbst, dass die Verwendung von Disconnected Recordsets nicht geeignet ist, wenn Sie eine Datenbanklösung einsetzen, bei der es auf Aktualität der Daten ankommt.

Anwendungsbeispiele für
“Disconnected Recordsets”

Nicht nur für Internet-Anwendungen können Disconnected Recordsets hilfreich sein – auch Ihre Datenbankanwendung können Sie unter Umständen mit einer Leistungssteigerung versehen, wenn Sie statische Daten mit einem Disconnected Recordset in den Arbeitsspeicher verlagern. Die folgenden Beispiele verdeutlichen dies:

  • Formularkonfigurationen: Sie speichern das Design und die Formate der Steuerelemente aller Formulare in Tabellen Ihrer Datenbank. Beim öffnen eines Formulars werden die Konfigurationsdaten für das Formular und für die in diesem Formular befindlichen Steuerelemente aus der Datenbank ausgelesen und auf das Formular angewendet.
  • SQL-Anweisungen: Um Ihre Applikation flexibel zu halten, speichern Sie alle SQL-Anweisungen in einer Relation Ihrer Anwendung anstatt sie als separate Abfrageobjekte zu speichern. Wenn eine SQL-Anweisung ausgeführt werden soll, lesen Sie den entsprechenden Text aus der Tabelle ein und führen ihn anschließend aus.
  • Meldungen und Anweisungen: Sie verwenden eine Tabelle in Ihrer Datenbank, in der Sie alle Meldungen und Anweisungen abgespeichert haben. Bevor ein Dialog geöffnet wird, lesen Sie den anzuzeigenden Text aus dieser Tabelle aus.

Erstellen eines “Disconnected Recordsets”

Um die Verbindung eines Recordsets zur Datenbank zu trennen, müssen Sie lediglich die Eigenschaft ActiveConnection des Recordsets auf Nothing setzen. Dadurch behält das Recordset seine Eigenschaften und Daten, hat aber keine Verbindung mehr zur Datenquelle. Die folgenden Beispiele demonstrieren diese Technik.

Datenbankbeispiel für die Verwendung von “Disconnected Recordsets”

Das nachfolgende Beispiel soll die Vorteile von Disconnected Recordsets bei der täglichen Arbeit mit Microsoft Access verdeutlichen. Weiter oben finden Sie einige Beispiele für die Anwendung von Disconnected Recordset. Nun sollen Sie die oben beschriebenen Szenarien an einem einfachen Beispiel nachvollziehen.

Beschreibung des Szenarios und der
Zieldefinition

Gegeben sei eine Tabelle, in der Texte und Anweisungen Ihrer Anwendung gespeichert sind, die Sie während der Laufzeit dynamisch anzeigen. Diese Tabelle dient als Konfigurationstabelle für die MsgBox-Anweisung und ist wie in Bild 2 aufgebaut.

pic002.tif

Bild 2: Aufbau einer Tabelle zum Speichern von Meldungstexten

üblicherweise würde man den Text und die Konfiguration mit einer Funktion auslesen, die bei jedem Zugriff dynamisch auf die Relation zugreift (s. Listing 3). Der Aufruf der obigen Funktion erfolgt so:

Listing 3: Auslesen einer Message durch direkten Tabellenzugriff

Public Function fn_app_MessageText(MsgFlag As String) As String
     On Error GoTo ErrorHandler 
     If MsgFlag = vbNullString Then GoTo ExitCode 
         Dim rst As ADODB.Recordset
         Set rst = New ADODB.Recordset
         With rst
             Set .ActiveConnection = CurrentProject.Connection
             .CursorLocation = adUseClient
             .CursorType = adOpenForwardOnly
             .Source = "SELECT MsgText FROM tbl_sys_Messages WHERE MsgFlag = '" _
& MsgFlag & "'" .Open If Not rst Is Nothing Then If Not (.EOF And .BOF) Then fn_app_MessageText = !MsgText Else fn_app_MessageText = vbNullString End If End If End With ExitCode: On Error Resume Next Exit Function ErrorHandler: MsgBox Err.Description, vbInformation, "fn_app_MessageText" Resume ExitCode End Function Dim Result as String Result = fn_app_MessageText("MeinMessageFlag") Debug.Print Result

So weit, so gut – leider wird jedes Mal, wenn Sie eine Meldung ausgeben möchten, eine Verbindung zur Datenbank hergestellt und anschließend eine Abfrage auf die Tabelle durchgeführt. Das macht eigentlich keinen Sinn, da ja in der Regel die Meldungen nicht so häufig aktualisiert werden.

Ziel der überarbeitung soll nun sein, dass für zukünftige Erweiterungen der Zugriff auf Konfigurationen nicht mehr mittels einzelner Funktionen, sondern lediglich durch die Methoden einer Klasse stattfindet.

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

Schreibe einen Kommentar