Home > Artikel > Ausgabe 11/2015 > DAO-Objekte und -Auflistungen, Teil II

DAO-Objekte und -Auflistungen, Teil II

Achtung: Sie sind nicht angemeldet. Wenn Sie Abonnent sind und sich anmelden, lesen Sie den kompletten Artikel, laden das PDF herunter oder probieren die Beispieldatenbank aus (sofern vorhanden).

Waren Containers, Documents und Properties Thema der letzten Ausgabe über DAO-Objekte, so geht es diesmal abschließend um Relations und Workspaces. Dabei handelt es sich zum einen um die Abbildung und Manipulation von Tabellenbeziehungen im Objektmodell, zum anderen um die sogenannten Arbeitsbereiche der Access Database Engine. Erfahren Sie, wie Tabellenbeziehungen einer Datenbank ermittelt und neu angelegt werden können.

Beispieldatenbank

Die Beispiele dieses Artikels finden Sie in der Datenbank 1511_DAORelations.accdb

Beziehungsbeispiel

Die Beispieldatenbank enthält vier uns mittlerweile wohlbekannte Tabellen, die über einige Beziehungen miteinander verknüpft sind. Zu den Feldern IDAnrede, IDOrt und IDLand der Tabelle tblAdressen existieren drei Nachschlagetabellen, die mit ihr auf unterschiedliche Weise in Beziehung stehen (siehe Bild 1). Für unsere Zwecke wurden die Beziehungen zum Testen auf etwas eigentümliche Weise modifiziert, die so allerdings keinen rechten Sinn mehr ergeben.

Beziehungslayout der Beispieldatenbank

Bild 1: Beziehungslayout der Beispieldatenbank

Bild 2 zeigt die Einstellungen für die Beziehung zwischen Adressen- und Anreden-Tabelle. Die Referenzielle Integrität wurde ausgeschaltet, aber der Typ mit 1:n beibehalten. Die Einstellungen für die Nachschlagetabelle zu Orten findet sich in Bild 3. Hier wurde nichts verändert. Schließlich stellt Bild 4 die Beziehung für die Länder-Tabelle dar, bei der jeweils zwei Felder verknüpft wurden. Neben dem eigentlichen Primärschlüsselfeld ID zu IDAnrede ist zusätzlich der Ländername Land selbst in der zweiten Zeile 1:n-verknüpft. Außerdem ist der Typ der Beziehung, erreichbar über die Schaltfläche Verknüpfungstyp..., auf den dritten Modus eingestellt, was sie zu einer Left-Join-Beziehung macht (Bild 5) Mit diesen Vorgaben lässt sich Referenzielle Integrität ohnehin nicht mehr festlegen, weil keine Eindeutigkeit mehr gegeben ist.

Einstellungen für die Beziehung zur Tabelle tblOrte

Bild 2: Einstellungen für die Beziehung zur Tabelle tblOrte

Verknüpfungstyp der Beziehung zu tblLaender

Bild 3: Verknüpfungstyp der Beziehung zu tblLaender

Einstellung für die Beziehung zur Tabelle tblLaender

Bild 4: Einstellung für die Beziehung zur Tabelle tblLaender

Einstellungen der Beziehung zur Tabelle tblAnreden

Bild 5: Einstellungen der Beziehung zur Tabelle tblAnreden

Beziehungen auslesen

Für die Beziehungen einer Datenbank ist über das VBA-Objekt Database deren Auflistungseigenschaft Relations zuständig. Die kurze Routine GetRelations in Listing 1 macht deutlich, wie die einzelnen Relation-Objekte in einer For-Each-Schleife durchlaufen werden können.

Sub GetRelations()

     Dim dbs As Database

     Dim rel As DAO.Relation

     

     Set dbs = CurrentDb

     For Each rel In dbs.Relations

         Debug.Print rel.Name

     Next rel

End Sub

Listing 1: Prozedur zum Durchlaufen der DAO-Auflistung Relations

Zunächst wird die Database-Variable dbs über die Funktion CurrentDb auf eine aktuelle Instanz der Datenbank gesetzt. Als Schleifenvariable kommt die Variable rel vom Typ DAO.Relation zum Einsatz. Im VBA-Direktfenster wird dann lediglich der Name der Beziehung ausgegeben. Als Ergebnis erhalten Sie dies:

MSysNavPaneGroupCategoriesMSysNavPaneGroupsMSysNavPaneGroupsMSysNavPaneGroupToObjectstblAnredentblAdressentblLaendertblAdressentblOrtetblAdressen

Dass Beziehungen überhaupt Namen haben, ist nicht so selbstverständlich, denn diese tauchen in der Oberfläche von Access nirgendwo auf. Im Beziehungsfenster sind sie auch in den Eigenschaftsdialogen nicht angegeben. Wie Sie sehen können, leiten sich die Namen aus den an der Beziehung beteiligten Tabellen ab. Die ersten beiden oben angegebenen Beziehungen sind übrigens in jeder Datenbank im Access 2007-Format vorhanden. Access legt sie selbst an.

Diese speziellen MSys-Tabellen dienen der Verwaltung und Steuerung des Navigationsbereichs.

Weiten wir nun die einfache Prozedur aus Listing 1 einmal ab, um mehr über die Beziehungen zu erfahren. Die Routine in Listing 2 hat den gleichen Grundaufbau, gibt aber neben den Namen auch noch die an der Verknüpfung beteiligten Tabellen über die Eigenschaften Table und ForeignTable der jeweiligen Relations-Objekte wieder. Das Ergebnis, hier unter Ausschluss der MSys-Beziehungen:

Sub GetRelationsTables()

     Dim dbs As Database

     Dim rel As DAO.Relation

     

     Set dbs = CurrentDb

     For Each rel In dbs.Relations

         Debug.Print rel.Name

         Debug.Print , rel.Table

         Debug.Print , rel.ForeignTable

         Debug.Print , rel.Attributes

     Next rel

End Sub

Listing 2: Ausgabe weiterer Bezihungseigenschaften (Tabellen)

tblAnredentblAdressen

               tblAnreden

               tblAdressen

                2

tblLaendertblAdressen

               tblLaender

               tblAdressen

                33554434

tblOrtetblAdressen

               tblOrte

               tblAdressen

0

Table ist also jene Tabelle, welche den Primärschlüssel in der Beziehung aufweist, ForeignTable die Tabelle mit dem Fremdschlüsselfeld. Die Zahl, die Attributes enthält, gibt darüber hinaus Aufschluss auf die Art der Beziehung. Es handelt sich hierbei um eine Kombination von Konstanten der Enumeration RelationAttributeEnum von DAO – siehe Objektkatalog. Der Wert 0 besagt dabei, dass die Beziehung Referenzielle Integrität fordert. Ist dies nicht der Fall, so steht hier eine 2. Die Zahl 33554434 ergibt sich aus der booleschen Addition von dbRelationRight (33554432) mit dbRelationDontEnforce (2), was eine Right-Verknüpfung ohne Referenzielle Integrität symbolisiert. Damit Sie den Typ nicht langwierig über die Analyse der Konstanten im Objektkatalog ermitteln müssen, gibt es im Modul mdlDAORelations die Funktion AttributesString, der Sie die Attributes-Konstante als Parameter übergeben und als Rückgabe eine Textrepräsentation des Typs erhalten:

  AttributesString(2)

> 1:n,Keine Ref. Integrität

  AttributesString(33554434)

> 1:n,Right Join,Keine Ref. Integrität

Sie können, statt die Relation-Methoden explizit anzugeben, auch deren Properties auslesen (Listing 3), und kommen damit zum gleichen Resultat:

Sub GetRelationsProps()

     Dim dbs As Database

     Dim rel As DAO.Relation

     Dim daoPrp As DAO.Property

     

     Set dbs = CurrentDb

     For Each rel In dbs.Relations

         Debug.Print rel.Name

         For Each daoPrp In rel.Properties

             Debug.Print , _

                 daoPrp.Name, _

                 daoPrp.Value

         Next daoPrp

     Next rel

End Sub

Listing 3: Durchlaufen der Properties-Auflistungen der Relations

tblAnredentblAdressen

     Name tblAnredentblAdressen

     Table tblAnreden

     ForeignTable tblAdressen

     Attributes 2

     PartialReplica Falsch

tblLaendertblAdressen

     Name tblLaendertblAdressen

     Table tblLaender

     ForeignTable tblAdressen

     Attributes 33554434

     PartialReplica Falsch

tblOrtetblAdressen

     Name tblOrtetblAdressen

     Table tblOrte

     ForeignTable tblAdressen

     Attributes 0

PartialReplica Falsch

Hier schleicht sich noch die Eigenschaft PartialReplica ein, die uns nicht weiter interessiert, weil sie nur für replizierte Datenbanken von Belang ist, die ohnehin seit geraumer Zeit nicht mehr direkt von Access unterstützt werden.

Nun haben wir zwar die Tabellen einer Beziehung ermittelt, wissen aber noch nicht, welche Felder genau aus ihnen miteinander verknüpft sind. Die Fields-Auflistung eines Relation-Objekts jedoch gibt uns darüber Auskunft. Sie kann auf analoge Weise durchlaufen werden, wie die Properties (siehe Listing 4). Für jedes Feld fld eines Relation-Objekts werden hier die Eigenschaften Name und ForeignName ausgelesen und mit den jeweiligen Tabellennamen kombiniert, so dass sich dieses Ergebnis zeigt:

Sub GetRelationsFields()

     Dim dbs As Database

     Dim rel As DAO.Relation

     Dim fld As DAO.Field

     

     Set dbs = CurrentDb

     For Each rel In dbs.Relations

         Debug.Print rel.Name

         For Each fld In rel.Fields

             Debug.Print , _

                 rel.Table & "." & _

                 fld.Name & " > " & _

                 rel.ForeignTable & _

                 "." & fld.ForeignName

         Next fld

     Next rel

End Sub

Listing 4: Durchlaufen der Fields-Auflistungen der Relations

tblAnredentblAdressen

   tblAnreden.ID > tblAdressen.IDAnrede

tblLaendertblAdressen

   tblLaender.ID > tblAdressen.IDLand

   tblLaender.Land > tblAdressen.Land

tblOrtetblAdressen

tblOrte.ID > tblAdressen.IDOrt

Am zweiten Eintrag zur Länder-Beziehung wird deutlich, dass zwei Felder verknüpft wurden, die Fields-Auflistung also zwei Elemente enthält. Obwohl übrigens das Field-Objekt als DAO.Field ausgewiesen ist, kennt es nur genau diese zwei Eigenschaften Name und ForeignName. Alle anderen Methoden des Objekts schlagen hier fehl.

Umgekehrt kann ein Field-Objekt etwa eines Recordsets, wiewohl vom gleichen Typ, mit diesen beiden Eigenschaften nichts anfangen – eine etwas seltsame Implementation des DAO-Objektmodells.

Fügen wir nun unsere Erkenntnisse zusammen und erstellen damit eine Routine, die alle relevanten Teile der Beziehungen auswirft, wie in Listing 5. Das Ergebnis ist dort direkt angehängt.

Sub GetRelationsComplete()

     Dim dbs As Database

     Dim rel As DAO.Relation

     Dim fld As DAO.Field

     

     Set dbs = CurrentDb

     For Each rel In dbs.Relations

         Debug.Print "Beziehungsname: " & rel.Name

         Debug.Print , "Typ: " & AttributesString(rel.Attributes)

         For Each fld In rel.Fields

             Debug.Print , "Feldverknüpfung: " & rel.Table & _

                         "." & fld.Name & " <> " & _

                         rel.ForeignTable & "." & fld.ForeignName

         Next fld

     Next rel

End Sub

'Beziehungsname: tblAnredentblAdressen

' Typ: 1:n, Keine Ref. Integrität

' Feldverknüpfung: tblAnreden.ID <> tblAdressen.IDAnrede

'Beziehungsname: tblLaendertblAdressen

' Typ: 1:n, Right Join, Keine Ref. Integrität

' Feldverknüpfung: tblLaender.ID <> tblAdressen.IDLand

' Feldverknüpfung: tblLaender.Land <> tblAdressen.Land

'Beziehungsname: tblOrtetblAdressen

' Typ: 1:n, Ref. Integrität

' Feldverknüpfung: tblOrte.ID <> tblAdressen.IDOrt

Listing 5: Diese kurze Prozedur gibt alle DAO-Informationen zu den Beziehungen einer Datenbank aus

Beziehungen erstellen

Zwar werden Sie in der Regel die Beziehungen einer Datenbank über das Beziehungsfenster von Access anlegen, doch manchmal gibt es Fälle, in denen eine Datenbank komplett über VBA erzeugt und bestückt wird. Der Vollständigkeit halber sei daher die Vorgehensweise geschildert (Listing 6).

Function CreateRelationVBA(sName As String, _

            sTable1 As String, sField1 As String, _

            sTable2 As String, sField2 As String, _

            Optional lType As RelationAttributeEnum) As Boolean

     Dim dbs As Database

     Dim rel As DAO.Relation

     Dim fld As DAO.Field

     

     Set dbs = CurrentDb

     Set rel = dbs.CreateRelation(sName, sTable1, sTable2, lType)

     Set fld = rel.CreateField(sField1)

     fld.ForeignName = sField2

Sie haben das Ende des frei verfügbaren Teil dieses Artikels erreicht!

Wenn Sie mehr lesen und auf viele weitere Artikel zugreifen möchten, melden Sie sich als Abonnent unter Login an. Falls nicht, bestellen Sie doch einfach ein Jahresabonnement!