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

Gedrucktes Heft

Diesen Beitrag finden Sie in Ausgabe 5/2006.

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

Erfahren Sie, wie Sie Variablen sitzungsübergreifend in Datenbank-Properties speichern können.

Techniken

SMTP, VBA

Voraussetzungen

Access 2000 und höher

Beispieldatenbank

DBProperties.mdb

Persistente Variablen

Sascha Trowitzsch, Berlin

Komplexere Anwendungen benötigen in der Regel bestimmte Einstellungen, die ihr Verhalten oder manche Vorgabewerte bestimmen. In der Regel findet man im Menü einen Eintrag Optionen, der ein Dialogfenster für diese Einstellungen hervorbringt. Gespeichert werden diese Werte normalerweise in der Registry, wobei eine Installationsprozedur hier meist bereits Vorgabewerte setzt. Auch umfangreiche Access-Datenbanken brauchen häufig solche Voreinstellungen. Dieser Beitrag zeigt, wie Sie diese Werte in benutzerdefinierten Datenbankeigenschaften speichern.

Dauerhaft gespeicherte Werte

Ein Beispiel für eine Einstellung, die man über Anwendungssitzungen hinweg speichern könnte, ist die Position von Fenstern.

Wird ein Fenster erneut geöffnet, dann soll es die gleiche Position und Größe auf dem Bildschirm haben, wie beim letzten Schließen. Komfortabel wäre auch, wenn beim Starten der Datenbank automatisch das zuletzt geöffnete Formular sichtbar würde - möglichst noch mit dem Datensatz, in dem man sich zuletzt befunden hat. Im Beitrag Steuerelemente mit Gedächtnis (Shortlink 394) können Sie lesen, wie sich diese Einstellungen entweder in einer speziellen Tabelle oder in der Registry ablegen lassen.

Andere Wege wären INI-Dateien (Textdateien) oder auch persistente disconnected ADO-Recordsets: Immerhin lassen sich auch ADO-Recordsets als Dateien abspeichern.

Die letzten zwei genannten Möglichkeiten setzen die Existenz separater Dateien voraus, die Registry-Methode funktioniert nur innerhalb des Windows-Kontos des jeweiligen Benutzers. Die Tabellenlösung ist nicht schlecht, benötigt aber einiges an Code und eine Tabelle, die besser vor den Augen des Anwenders versteckt sein sollte.

Es gibt aber noch eine fünfte und einfache Lösung, die sich die benutzerdefinierten Eigenschaften des Database-Objekts zu Nutze macht. In der Beispieldatenbank finden Sie Anwendungsbeispiele dazu.

Database-Properties

Eine geöffnete Access-Datenbank im MDB-Format besitzt immer ein von der Bibliothek DAO abgeleitetes Database-Objekt.

Das ist selbst dann so, wenn kein Verweis auf die DAO-Bibliothek gesetzt ist. Das standardmäßig vorhandene Application-Objekt hat die Eigenschaften CurrentDb und DBEngine. Dabei ist DBEngine(0)(0) das eigentliche Database-Objekt, während CurrentDb eine kopierte Instanz desselben darstellt.

Und wie fast alle Objekte der DAO-Bibliothek hat auch das Database-Objekt eine Auflistung namens Properties.

Dahinter verbergen sich verschiedene Eigenschaften der Datenbank wie etwa Name (der Pfad zur MDB), Version (die JET-Version, unter der die Datenbank erstellt wurde) oder StartUpForm (das Formular, das beim Öffnen der Datenbank angezeigt wird, falls angegeben).

Access stellt diese Eigenschaften selbst ein, um dann beim Öffnen der MDB zu wissen, wie es mit der Datenbank verfahren soll.

Diese Eigenschaften sind eingebaut und können theoretisch weder per VBA gesetzt, noch gelöscht werden.

Zumindest äußert sich die Online-Hilfe von Access so - eine Fehlinformation, wie Sie später sehen werden.

Die einzelnen Versionen von Access enthalten außerdem unterschiedliche, aber abwärtskompatible Eigenschaften. (In der Betaversion Access 2007 sind etwa die Eigenschaften des neuen Navigationsbereichs hinzugekommen.)

Neben den eingebauten Properties lassen sich aber beliebige selbst definierte Eigenschaften erzeugen und dann Werte in ihnen speichern.

Property auslesen

Sie lesen eine Database-Eigenschaft per VBA entweder über den Namen der Eigenschaft oder über ihre Ordinalnummer aus:

Debug.Print CurrentDb.Properties("Name")

Debug.Print CurrentDb.Properties(1)

Ersetzt man die 1 in voriger Code-Zeile durch eine Variable, dann lassen sich alle Properties über eine Schleife auflisten:

For i = 0 To 1000

    Debug.Print _
        Currentdb.Properties(i).Name

Next i

Diese Schleife wird nach einigen Durchläufen einen Fehler hervorrufen, nämlich dann, wenn i einen Wert hat, der keiner gültigen Ordinalzahl mehr entspricht.

Eleganter ist deshalb die folgende For Each-Schleife:

Dim prp As DAO.Property

For Each prp In CurrentDb.Properties

    Debug.Print prp.Name, prp.Value

Next prp

Neben den Namen der Eigenschaften gibt diese Routine gleichzeitig noch mit prp.Value die Werte derselben aus.

In der Beispieldatenbank finden Sie eine etwas ausführlichere und fehlerresistente Version dieser List-Funktion im Modul mdlProperties und in der Prozedur ListProperties.

Property setzen

Der Wert für eine Property wird durch einfache Zuweisung gesetzt:

CurrentDb.Properties("StartUpForm")= "frmStart"

Das ist eigentlich die Kurzform, denn eigentlich wird hier die Eigenschaft Value des Properties gesetzt (in einer Zeile):

CurrentDb.Properties
("StartUpForm").Value

Value ist jedoch die Default-Eigenschaft des Property-Objekts und kann daher weggelassen werden.

Der Datentyp einer Property ist Variant, daher kann die Property beliebige Werte annehmen. Es können also zum Beispiel Long-Werte, Strings oder Datumswerte übergeben werden.

Property erzeugen

Nun wird es interessant: Über die DAO-Methode CreateProperty kann man eine benutzerdefinierte Eigenschaft erzeugen:

CurrentDb.CreateProperty <Name>, _

    <Datentyp>, <Wert>

Der Datentyp ist eine der Konstanten der Enumeration DAO.DataTypeEnum - etwa dbText für einen String oder dbLong für einen Long-Integer. Der übergebene Wert muss dazu passen.

Mit obiger Code-Zeile befindet sich das Property noch quasi im luftleeren Raum - ohne Bezug zum Datenbank-Objekt. Erst durch das Zuweisen zur Properties-Auflistung des Datenbank-Objekts wird es dann auch gespeichert:

Dim prp As DAO.Property

Set prp = CurrentDb.CreateProperty _
    ("Autor", dbText, "Trowitzsch")

CurrentDB.Properties.Append prp

Somit ist in der benutzerdefinierten Eigenschaft "Autor" der Datenbank der Wert "Trowitzsch" gesetzt. Eine längere Alternative zu diesem Code wäre diese:

Dim prp As DAO.Property

Set prp = CurrentDb.CreateProperty _
    ("Autor")

prp.Type = dbText

prp.Value = "Trowitzsch"

CurrentDB.Properties.Append prp

Property löschen

Das Löschen einer Datenbankeigenschaft erfolgt mit dieser Anweisung:

CurrentDb.Properties.Delete "Autor"

Normalerweise dürfte das selten notwendig sein. Ein Fall wäre, dass Sie eine Property mit einem Datentyp angelegt hätten, diesen aber etwa von dbText in dbLong umwandeln wollten. Das geht nämlich nicht: Die Zuweisung eines neuen Datentyps führt zu einem Laufzeitfehler. Sie müssen die Property erst löschen und unter dem gleichen Namen mit dem neuen Datentyp anlegen.

Hinweis

Wenn Sie versuchen, eine eingebaute Access-Eigenschaft zu löschen, beispielsweise Version, so löst das einen Fehler aus. Soweit entspricht dies der Aussage in der Online-Hilfe. Fraglich ist hier nur, was unter "eingebauter" Eigenschaft zu verstehen ist. So existiert ein Property Build, das die Versionsnummer der msaccess.exe zurückgibt, mit der die Datenbank erstellt wurde. Man kann die Property löschen, sie wird beim nächsten Start der Datenbank aber automatisch wieder gesetzt. Das lässt sich auch noch mit weiteren von Access erzeugten Properties machen, wovon allerdings abzuraten ist. Es kann dazu führen, dass die Datenbank sich nicht mehr starten lässt. Im Versuch habe ich festgestellt, dass eine auf diese Weise "behandelte" Datenbank mit keinerlei Reparaturversuchen wieder zum Leben zu erwecken war. Erstaunlicherweise gelang dann allerdings das Öffnen in der Beta-Version von Access 2007 ... (

Persistente Variablen mit
Properties

Mit diesen Grundlagen können Sie nun öffentliche Routinen basteln, mit deren Hilfe sich von überall aus der Datenbank heraus Werte dauerhaft speichern und auslesen lassen. In der Beispieldatenbank finden Sie etwa die in Quellcode 1 dargestellte Routine.

Die Prozedur SetAProperty erwartet als Parameter die Angabe eines Eigenschaftennamens in sName und des Wertes in AValue.

Die Routine versucht zunächst, eine Objektvariable oPrp auf die Eigenschaft zu setzen. Schlägt dies fehl, weil etwa die Eigenschaft nicht existiert, so wird sie im If-Teil neu angelegt.

Da dabei die Angabe des Datentyps zwingend notwendig ist, muss dieser aus dem übergebenen Wert selbst bestimmt werden. Das erledigt die VBA-Funktion VarType(). Leider stimmen die von dieser Funktion zurückgegebenen Konstanten nicht mit den Datentypen von DAO überein. Deshalb wird eine Übersetzung der Konstanten in einer Hilfsfunktion TranslateType vorgenommen, die hier nicht abgebildet ist.

Quellcode 1: Routine zum dauerhaften Speichern einer "Variablen"

Sub SetAProperty(sName, AValue As Variant)

    Dim dbs As Database

    Dim oPrp As DAO.Property

    Set dbs = DBEngine(0)(0)

    On Error Resume Next

    Set oPrp = dbs.Properties(sName)

    If oPrp Is Nothing Then

        On Error GoTo 0

        Set oPrp = dbs.CreateProperty(sName, TranslateType(AValue), AValue)

        dbs.Properties.Append oPrp

    Else

        oPrp.Value = AValue

    End If

    Set oPrp = Nothing

    Set dbs = Nothing

End Sub

Die folgende Version ist wesentlich kürzer:

Function GetAProperty(sName) As Variant

    On Error Resume Next

    GetAProperty = DBEngine(0)(0). _
        Properties(sName).Value

End Function

Ihnen fällt vielleicht auf, dass in diesen beiden Quellcodes statt CurrentDb die Variante DBEngine(0)(0) zum Einsatz kommt. Grund ist die wesentlich höhere Geschwindigkeit dieses Ausdrucks.

Als Beleg das Resultat eines Tests, den Sie mit der Prozedur BenchmarkSetGetProp der Beispieldatenbank auch selbst ausführen können:

Wird beim Auslesen CurrentDb.Properties verwendet, dann lässt sich die Funktion GetAProperty auf aktueller Hardware circa 1.500 Mal pro Sekunde aufrufen. Mit DBEngine(0)(0).Properties erhöht sich dieser Wert auf ca. 200.000!

Das zeigt, dass sich diese benutzerdefinierten Datenbank-Properties auch gut in Schleifenkonstrukten verwenden lassen, weil das Auslesen nur sehr wenig Zeit kostet.

Beispielanwendung

In der Beispieldatenbank DBProperties.mdb finden Sie einige Anwendungsfälle für die in Kapitel 3 abgebildeten Routinen.

So werden die Fensterpositionen der beiden Formulare frmKundenSimple und frmKundenKomplex beim Schließen in einer benutzerdefinierten Eigenschaft gespeichert und beim nächsten Öffnen wiederhergestellt.

Des Weiteren öffnet sich beim Start der Datenbank nach dem Intro-Formular immer das Beispielformular, das Sie zuletzt geöffnet hatten.

Die dafür verantwortliche Code-Zeile sieht so aus:

DoCmd.OpenForm GetAProperty("LastForm")

Im UnLoad-Ereignis der Formulare steht jeweils:

SetAProperty "LastForm", Me.Name

Außerdem wird jedes Formular mit dem Datensatz geöffnet, mit dem man es verlassen hat. Dazu wird beim Entladen in einer Eigenschaft der Primärschlüssel des Datensatzes gespeichert und beim Öffnen mit Me.Recordset.FindFirst wieder angesprungen. Das funktioniert im Formular frmKundenKomplex sogar für den Detaildatensatz des eingebetteten Unterformulars.

Download

Download

Die .zip-Datei enthält folgende Dateien:

DBProperties.mdb

Beispieldateien downloaden

© 2003-2010 André Minhorst Alle Rechte vorbehalten.