1:n-Beziehungen in Unterformularen

Meistens zeigt man 1:n-Beziehungen in einem Haupt- und einem Unterformular an. Was aber, wenn man die Datensätze beider Seiten im überblick anzeigen möchte – etwa wenn Sie alle Kategorien in einer Liste und die Artikel zur ausgewählten Kategorie in einer anderen Liste darzustellen Oder, um es noch eine Nummer komplizierter zu machen, im Hauptformular die Kunden, im ersten Unterformular ihre Bestellungen und im zweiten Unterformular die Bestellpositionen der im ersten Unterformular ausgewählten Bestellung Dann ist meist ein kleiner Trick erforderlich, um dies zu bewerkstelligen – wie der vorliegende Beitrag zeigt.

Herkömmliche Darstellung

Normalerweise verwendet man zur Darstellung von 1:n-Beziehungen ein Haupt- und ein Unterformular. Das Hauptformular zeigt dabei die Datensätze der Mastertabelle an, also beispielsweise die Daten der Tabelle tblKategorien. Die Anzeige ist dabei allerdings auf Formularansicht eingestellt, was bewirkt, dass nur die Daten jeweils eines Datensatzes im Formular erscheinen.

Das Unterformular zeigt die Daten der Detailtabelle an, also der Tabelle, die über ein Fremdschlüsselfeld mit den Datensätzen der Mastertabelle verknüpft ist. In unserem Beispiel handelt es sich dabei um die Tabelle tblArtikel.

Das Formular aus Bild 1 ist genau wie beschrieben aufgebaut – es zeigt die Daten der Tabelle tblKategorien im Hauptformular und die der Tabelle tblArtikel im Unterformular an. Damit das Unterformular nur die Daten der Tabelle tblArtikel anzeigt, die über das Fremdschlüsselfeld KategorieID mit dem aktuellen Datensatz der Tabelle tblKategorien im Hauptformular verknüpft sind, trägt man für die Eigenschaft Verknüpfen von des Unterformular-Steuerelements den Namen des Fremdschlüsselfeldes der Tabelle im Unterformular ein (hier KategorieID) und für die Eigenschaft Verknüpfen nach den Namen des Primärschlüsselfeldes der im Hauptformular abgebildeten Tabelle tblKategorien. Das Ergebnis finden Sie in Bild 2 vor: Sie können durch die Datensätze im Hauptformular navigieren und das Unterformular zeigt jeweils nur die passenden Datensätze an.

1:n-Beziehung in Haupt- und Unterformular mit Verknüpfungseigenschaften

Bild 1: 1:n-Beziehung in Haupt- und Unterformular mit Verknüpfungseigenschaften

1:n-Beziehung in Haupt- und Unterformular

Bild 2: 1:n-Beziehung in Haupt- und Unterformular

Zwei Unterformulare

Nun gehen wir eine Stufe weiter: Wir wollen die Kategorien nicht mehr im Hauptformular anzeigen, sondern in einem weiteren Unterformular. So hat der Benutzer nicht nur die mit einer Kategorie verknüpften Artikel im überblick, sondern kann auch gleich die Liste der Kategorien einsehen und die gewünschte Kategorie auswählen.

Um dies zu erreichen, legen Sie zunächst ein neues Hauptformular namens frmKategorienArtikelUFUF an (UFUF für Unterformular/Unterformular). Dann erstellen Sie ein Formular namens sfmKategorienUFUF, das die Tabelle tblKategorien als Datenherkunft verwendet und seine Daten in der Datenblattansicht anzeigt. Auf ähnliche Weise erstellen Sie das Formular sfmArtikelUFUF, das Sie mit der Tabelle tblArtikel füllen – ebenfalls in der Datenblattansicht. Ziehen Sie beide Unterformulare in das Hauptformular. Da das Hauptformular seinerseits keine Daten anzeigen soll, entfernen Sie der übersichtlichkeit halber Elemente wie die Navigationsschaltflächen, Bildlaufleisten und Datensatzmarkierer, indem Sie die entsprechenden Eigenschaften jeweils auf den Wert Nein einstellen. Beide Formulare ziehen Sie nun nebeneinander in das Hauptformular frmKategorienArtikelUFUF, sodass dieses wie in Bild 3 aussieht.

Zwei Unterformulare, die miteinander verknüpft werden sollen

Bild 3: Zwei Unterformulare, die miteinander verknüpft werden sollen

Ein Wechsel in die Formularansicht zeigt, dass die Daten schon einmal wie gewünscht erscheinen (s. Bild 4). Allerdings filtert das rechte Unterformular seine Daten noch nicht nach dem aktuell im linken Unterformular angezeigten Wert.

Aktuell zeigen beide Formulare alle Daten an, aber die Artikel werden nicht nach der aktuellen Kategorie gefiltert.

Bild 4: Aktuell zeigen beide Formulare alle Daten an, aber die Artikel werden nicht nach der aktuellen Kategorie gefiltert.

Dummerweise erkennt Access auch nicht automatisch, was wir hier vorhaben, daher füllt es die beiden Eigenschaften Verknüpfen von und Verknüpfen nach nicht automatisch aus wie im vorherigen Beispiel. Kommen wir hier überhaupt mit den beiden Eigenschaften aus Ein Versuch, für die Eigenschaft Verknüpfen Nach einen direkten Bezug zum anderen Unterformular unterzubringen wie in Bild 5, scheitert allerdings – Access fragt den Ausdruck Parent!sfmKategorienUFUF!KategorieID in einer Inputbox ab und das Unterformular sfmArtikelUFUF bleibt leer.

Diese Einstellung funktioniert nicht.

Bild 5: Diese Einstellung funktioniert nicht.

Allerdings sollte man immer mehrere Varianten ausprobieren und vor allem eventuelle Tipp- oder Syntaxfehler ausschließen. In diesem Fall war es kein Syntaxfehler, Access kann den zunächst verwendeten Ausdruck schlicht nicht verarbeiten. Mit dem folgenden Ausdruck für die Eigenschaft Verknüpfen nach haben wir allerdings mehr Erfolg:

Forms!frmKategorienArtikelUFUF! sfmKategorienUFUF!KategorieID

Das Unterformular sfmArtikelUFUF zeigt nach dem Wechsel in die Entwurfsansicht die korrekten Daten an, also nur diejenigen Artikel, die zur aktuellen Kategorie gehören. Dummerweise ist die Begeisterung nach dem Wechsel zu einer anderen Kategorie schon wieder erledigt: Die zuvor angezeigten Artikel werden nicht gegen die der nun eingestellten Kategorie ausgetauscht.

Erst wenn man links eine neue Kategorie auswählt, dann in das rechte Unterformular klickt und dann mit der Taste F5 die Datenherkunft aktualisiert, zeigt dieses Unterformular die gewünschten Artikel-Datensätze an. Das ist allerdings ein wenig umständlich.

Also kommen wir nicht umhin, mit einer kleinen VBA-Prozedur nachzuhelfen. Da das rechte Unterformular immer dann aktualisiert werden soll, wenn der Benutzer im linken Unterformular einen anderen Datensatz ausgewählt hat, benötigen wir eine Ereignisprozedur, die durch das Ereignis Beim Anzeigen des linken Unterformulars ausgelöst wird.

Das wäre also vom linken Unterformular aus ein Verweis auf das Parent-Objekt und von dort aus auf das Unterformular-Steuerelement sfmArtikelUFUF und dann auf das darin enthaltene Form-Objekt. Für dieses soll dann die Requery-Methode ausgeführt werden, was wie folgt aussehen könnte:

Private Sub Form_Current()
     Me.Parent!sfmArtikelUFUF.Form.Requery
End Sub

Access macht uns aber beim öffnen des Formulars mit der Fehlermeldung aus Bild 6 einen Strich durch die Rechnung.

Fehlermeldung beim öffnen des Formulars

Bild 6: Fehlermeldung beim öffnen des Formulars

In einem solchen Fall klickt man am besten auf die Debuggen-Schaltfläche und untersucht die aktuelle Situation durch entsprechende Prüfungen im Direktfenster des VBA-Fensters. Möglicherweise haben wir ja irgendwo einen Syntaxfehler eingebaut

Also hangeln wir uns durch die referenzierten Elemente, wobei wir uns von links nach rechts vorarbeiten und am besten immer eine gängige Eigenschaft des jeweils referenzierten Elements abfragen. Wir starten mit dieser Abfrage:

  Me.Parent.Name
frmKategorienArtikelUFUF

Dies klappt also. Gehen wir einen Schritt weiter:

  Me.Parent.sfmArtikelUFUF.Name
sfmArtikelUFUF

Und noch einen Schritt:

  Me.Parent.sfmArtikelUFUF.Form.Name

Hier erscheint dann die bereits bekannte Fehlermeldung. Das im Unterformularsteuerelement enthaltene Formular ist also anscheinend nicht verfügbar. Das kann natürlich sein, denn die Unterformulare werden ja in einer bestimmten Reihenfolge geladen – möglicherweise ist das Unterformular sfmArtikelUFUF ja noch gar nicht existent, wenn die obige Ereignisprozedur versucht, darauf zuzugreifen.

Wenn Sie an dieser Stelle auf die Schaltfläche Beenden der Fehlermeldung klicken, erscheint das Formular mit beiden Unterformularen, wobei die Artikel entsprechend dem aktuell markierten ersten Eintrag des Kategorien-Unterformulars gefiltert werden – aber dies war ja auch schon ohne den Einsatz der Ereignisprozedur der Fall.

Wenn Sie nun allerdings eine andere Kategorie wählen, zeigt das rechte Unterformular plötzlich die zugeordneten Artikel an – die Ereignisprozedur scheint also doch korrekt zu funktionieren, nur eben nicht beim öffnen des Formulars.

Wir brauchen uns also nur darum zu kümmern, dass das Unterformular sfmArtikelUFUF nur aktualisiert wird, wenn es bereits vorhanden ist. Da dies beim öffnen des Hauptformulars automatisch geschieht, können wir die Prüfung aus Listing 1 in die Ereignisprozedur einbauen.

Private Sub Form_Current()
     Dim strForm As String
     On Error Resume Next
     strForm = Me.Parent!sfmArtikelUFUF.Form.Name
     On Error GoTo 0
     If Len(strForm) > 0 Then
         Me.Parent!sfmArtikelUFUF.Form.Requery
     End If
End Sub

Listing 1: Aktualisieren des Unterformulars sfmArtikelUFUF

Diese versucht, nach vorheriger Deaktivierung der Fehlerbehandlung den Namen des Unterformulars einzulesen. Ist das Formular bereits vorhanden, ist strForm danach mit dem Namen des Formulars gefüllt. Dies prüft eine If…Then-Bedingung und aktualisiert in diesem Fall die Datenherkunft des Unterformulars sfmArtikelUFUF.

Elegantere Lösung

Nun ist dies nicht die schönste Lösung. Das eine Unterformular weiß nicht, wann das andere Unterformular geladen wird – das ist nicht optimal. Wir wollen zunächst einmal betrachten, in welcher Reihenfolge die Unterformulare eigentlich geladen werden – und wie diese Zeitpunkte sich zum Laden des Hauptformulars verhalten. Also fügen Sie sowohl für das Hauptformular als auch für die beiden Unterformulare jeweils eine Ereignisprozedur für das Ereignis Beim Laden hinzu.

Wir benötigen keine weiteren Anweisungen, lediglich je einen Haltepunkt in der ersten Zeile der jeweiligen Prozedur. Wenn Sie das Formular nun öffnen, zeigt der VBA-Editor nacheinander die Haltepunkte in der entsprechenden Reihenfolge an. Wir stellen fest: Das Unterformular sfmKategorienUFUF lädt als erstes, dann folgt sfmArtikelUFUF und schließlich das Hauptformular.

Ein paar weitere Experimente, in denen wir die Unterformulare nacheinander ausschneiden und neu anlegen, zeigen, dass das Hauptformular immer zuletzt geladen wird.

Bei den Unterformularen richtet sich die Reihenfolge offensichtlich danach, in welcher Reihenfolge die Unterformulare zum Hauptformular hinzugefügt wurden.

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