IntelliSense für Tabellen und Felder

Wenn Sie mit dem VBA-Editor arbeiten und dort gelegentlich SQL-Anweisungen eingeben, müssen Sie die Namen der verwendeten Tabellen, Abfragen und Felder entweder kennen oder immer wieder zum Access-Fenster wechseln, um die Tabellen zu öffnen und die fehlenden Informationen nachzuschlagen. Dies können Sie mit dem hier beschriebenen Vorgehen in Zukunft wesentlich vereinfachen!

Beispiele für solche Texte sind die folgenden:

Set rst = db.OpenRecordset("SELECT tblArtikel.ArtikelID, tblArtikel.Artikelname 
FROM tblArtikel", dbOpenDynaset)
db.Execute "UPDATE tblArtikel SET tblArtikel.Einzelpreis = 10 
WHERE tblArtikel.Artikelname LIKE 'Chai'"

Wie wäre es denn, wenn Sie die SQL-Anweisung mit IntelliSense-Unterstützung erstellen könnten? Dies könnten Sie wie in folgendem Bild vom Direktfenster aus erledigen oder auch direkt im Codefenster:

Dazu geben Sie einfach nur die ersten Zeichen des gesuchten Tabellennamens ein und betätigen dann die Tastenkombination für IntelliSense, nämlich Umschalt + Leertaste.

Und es kommt noch besser: Wenn Sie den Tabellennamen eingegeben haben und einen Punkt hinzufügen, zeigt IntelliSense alle Feldnamen an:

Den so zusammengestellten SQL-Ausdruck müssen Sie nur noch mit vorangehendem

db.OpenRecordset("...", dbOpenDynaset) 

ausstatten, schon ist die SQL-Anweisung fertig.

Wie funktioniert das Ganze? Nun: Wir haben für die Tabelle tblArtikel eine gleichnamige Klasse erstellt, deren Inhalt zunächst wie folgt aussieht:

Public Property Get ArtikelID()
ArtikelID = rst!ArtikelID
End Property
Public Property Get Artikelname()
Artikelname = rst!Artikelname
End Property
Public Property Get LieferantID()
LieferantID = rst!LieferantID
End Property
Public Property Get KategorieID()
KategorieID = rst!KategorieID
End Property
Public Property Get Liefereinheit()
Liefereinheit = rst!Liefereinheit
End Property
Public Property Get Einzelpreis()
Einzelpreis = rst!Einzelpreis
End Property
Public Property Get Lagerbestand()
Lagerbestand = rst!Lagerbestand
End Property
Public Property Get BestellteEinheiten()
BestellteEinheiten = rst!BestellteEinheiten
End Property
Public Property Get Mindestbestand()
Mindestbestand = rst!Mindestbestand
End Property
Public Property Get Auslaufartikel()
Auslaufartikel = rst!Auslaufartikel
End Property

Das erklärt, warum nach Eingabe des Punktes die einzelnen Feldnamen angezeigt werden – es handelt sich schlicht um Property Get-Eigenschaften. Aber warum können wir einfach so die Klassennamen wie tblArtikel per IntelliSense nutzen? Dies gelingt bei herkömmlichen Klassen nicht. Wir haben an dieser Stelle einen kleinen Trick angewendet, der die Klasse ohne Instanzierung ausführbar macht. Dadurch erscheint auch der Klassenname direkt in der IntelliSense-Liste.

tblArtikel statt rst

Aber wir haben im gleichen Zuge noch ein cooles Feature zu der Klasse hinzugefügt. Damit können Sie nun direkt über den Tabellennamen auf die enthaltenen Daten zugreifen statt erst ein Recordset erstellen zu müssen. Das sieht dann etwa so aus:

Public Sub Test()
With tblArtikel
Do While Not .EOF
Debug.Print .ArtikelID, .Artikelname
.MoveNext
Loop
End With
End Sub

Neben den einzelnen Feldern stehen auch noch ein paar weitere Methoden und Eigenschaften wie MoveFirst, MoveLast, MovePrevious, MoveNext oder auch FindFirst zur Verfügung.

All dies erreichen wir durch entsprechende Methoden in der Klasse, die so aussehen:

Dim db As DAO.Database
Dim rst As DAO.Recordset

Private Sub Class_Initialize()
Set db = CurrentDb
Set rst = db.OpenRecordset("SELECT * FROM tblArtikel", dbOpenDynaset)
End Sub

Public Sub FindFirst(strFilter As String)
rst.FindFirst strFilter
End Sub

Public Sub MoveNext()
rst.MoveNext
End Sub

Public Sub MovePrevious()
rst.MovePrevious
End Sub

Public Sub MoveFirst()
rst.MoveFirst
End Sub

Public Sub MoveLast()
rst.MoveLast
End Sub

Public Function EOF() As Boolean
EOF = rst.EOF
End Function

Public Function BOF() As Boolean
BOF = rst.BOF
End Function

Die Klasse erstellt also direkt beim Initialisieren ein Database-Objekt und ein Recordset-Objekt mit allen Datensätzen der Tabelle. Über die Methoden und Eigenschaften können Sie dann genau wie bei einem Recordset-Objekt auf die Tabelle zugreifen.

Tabellenklassen per Code erzeugen

Nun wäre es etwas viel Aufwand, für jede Tabelle von Hand eine entsprechende Klasse zu erzeugen. Deshalb haben wir eine Prozedur geschrieben, welche die Klassen für alle mit tbl beginnenden Tabellen der Datenbank anlegt. Diese kopieren Sie einfach in ein Standardmodul und starten sie. Achtung: Sie benötigen einen Verweis auf die Bibliothek Microsoft Visual Basic For Applications Extensibility 5.3:

Hier ist der Code der Prozedur zum Erstellen der Klassen:

Public Sub TabelleZuKlasse()
Dim db As DAO.Database
Dim tdf As DAO.TableDef
Dim fld As DAO.Field
Dim objCodeModule As VBIDE.CodeModule
Dim objVBProject As VBIDE.VBProject
Dim objVBComponent As VBIDE.VBComponent
Dim strKlasse As String
Dim strCode As String
Set objVBProject = VBE.ActiveVBProject
Set db = CurrentDb
For Each tdf In db.TableDefs
If tdf.Name Like "tbl*" Then
On Error Resume Next
objVBProject.VBComponents.Remove objVBProject.VBComponents(tdf.Name)
On Error GoTo 0
End If
Next tdf
For Each tdf In db.TableDefs
If tdf.Name Like "tbl*" Then
Set objVBComponent = objVBProject.VBComponents.Add(vbext_ct_ClassModule)
objVBComponent.Name = tdf.Name
strCode = ""
strCode = strCode & "Dim db As DAO.Database" & vbCrLf
strCode = strCode & "Dim rst As DAO.Recordset" & vbCrLf
strCode = strCode & vbCrLf
strCode = strCode & "Private Sub Class_Initialize()" & vbCrLf
strCode = strCode & " Set db = CurrentDb" & vbCrLf
strCode = strCode & " Set rst = db.OpenRecordset(""SELECT * FROM " _
& tdf.Name & """, dbOpenDynaset)" & vbCrLf
strCode = strCode & "End Sub" & vbCrLf
strCode = strCode & vbCrLf
strCode = strCode & "Public Sub FindFirst(strFilter As String)" & vbCrLf
strCode = strCode & " rst.FindFirst strFilter" & vbCrLf
strCode = strCode & "End Sub" & vbCrLf
strCode = strCode & vbCrLf
strCode = strCode & "Public Sub MoveNext()" & vbCrLf
strCode = strCode & " rst.MoveNext" & vbCrLf
strCode = strCode & "End Sub" & vbCrLf
strCode = strCode & vbCrLf
strCode = strCode & "Public Sub MovePrevious()" & vbCrLf
strCode = strCode & " rst.MovePrevious" & vbCrLf
strCode = strCode & "End Sub" & vbCrLf
strCode = strCode & vbCrLf
strCode = strCode & "Public Sub MoveFirst()" & vbCrLf
strCode = strCode & " rst.MoveFirst" & vbCrLf
strCode = strCode & "End Sub" & vbCrLf
strCode = strCode & vbCrLf
strCode = strCode & "Public Sub MoveLast()" & vbCrLf
strCode = strCode & " rst.MoveLast" & vbCrLf
strCode = strCode & "End Sub" & vbCrLf
strCode = strCode & vbCrLf
strCode = strCode & "Public Function EOF() As Boolean" & vbCrLf
strCode = strCode & " EOF = rst.EOF" & vbCrLf
strCode = strCode & "End Function" & vbCrLf
strCode = strCode & vbCrLf
strCode = strCode & "Public Function BOF() As Boolean" & vbCrLf
strCode = strCode & " BOF = rst.BOF" & vbCrLf
strCode = strCode & "End Function" & vbCrLf
strCode = strCode & vbCrLf
For Each fld In tdf.Fields
strCode = strCode & "Public Property Get " & fld.Name & "()" & vbCrLf
strCode = strCode & " " & fld.Name & " = rst!" & fld.Name & vbCrLf
strCode = strCode & "End Property" & vbCrLf
Next fld
objVBComponent.CodeModule.AddFromString strCode
objVBComponent.Export CurrentProject.Path & "" & objVBComponent.Name
objVBProject.VBComponents.Remove objVBComponent
Open CurrentProject.Path & "" & tdf.Name For Input As #1
strKlasse = Input$(LOF(1), #1)
Close #1
strKlasse = Replace(strKlasse, "Attribute VB_PredeclaredId = False", _
"Attribute VB_PredeclaredId = True")
Open CurrentProject.Path & "" & tdf.Name For Output As #1
Print #1, strKlasse
Close #1
objVBProject.VBComponents.Import CurrentProject.Path & "" & tdf.Name
DoCmd.Save acModule, tdf.Name
End If
Next tdf
Set db = Nothing
End Sub

Probieren Sie es einfach einmal aus!

Dies war die Leseprobe dieses Artikels.
Melden Sie sich an, um auf den vollständigen Artikel zuzugreifen.

Bitte geben Sie die Zahlenfolge in das nachfolgende Textfeld ein

Die mit einem * markierten Felder sind Pflichtfelder.

  • das ist Ober-Klasse!

    als reiner VBA´ler ist es nicht leicht, darauf zu kommen....

  • Das ist echt innovativ

    Hallo Herr Minhorst,

    das nenne ich mal wirklich innovativ. Wirklich eine sehr schöne Lösung.

    Danke !!!

  • Sehr hilfreich

    Hallo Herr Minhorst ,
    so weit so gut aber eine Erweiterung schlage ich vor:
    Wenn reservierte Begriffe als Feldnamen genutz werden führt dies zu Laufzeitfehlern.
    Beispiel: Feldname FUNCTION oder TYPE:
    ....
    Dim xProperty
    ....
    For Each fld In tdf.Fields
    'Reservierte Begriffe abwandeln, führt zu Laufzeitfehlern
    If fld.Name = "FUNCTION" Or fld.Name = "TYPE" Then
    xProperty = fld.Name & "x"
    Else
    xProperty = fld.Name
    End If
    strCode = strCode & "Public Property Get " & xProperty & "()" & vbCrLf
    strCode = strCode & " " & xProperty & " = rst!" & fld.Name & vbCrLf
    strCode = strCode & "End Property" & vbCrLf
    Next fld
    mfg
    Michael Goos

  • Reservierte Begriffe ...

    Ich würde gegebenenfalls eine Fehlermeldung beim Erstellen der Klassen ausgeben, wenn der Entwickler reservierte Begriffe als Feldnamen verwendet. Aber Profis machen so etwas ja sowieso nicht ... ;-)

Passende Artikel
Access im Unternehmen Access im Unternehmen
124,00 € * 159,00 € *
Aktuell im Blog
Onlinebanking mit Access

Es ist geschafft: Endlich ist das Buch Onlinebanking mit Access fertiggeschrieben. Das war... [mehr]

Direktzugriff auf Tabellen und Felder

Die IntelliSense-Erweiterung für Tabellen und Felder hat mir soviel Spaß gemacht, dass ich gleich... [mehr]

IntelliSense für Tabellen und Felder

Wenn Sie mit dem VBA-Editor arbeiten und dort gelegentlich SQL-Anweisungen eingeben, müssen Sie... [mehr]

Download Access und SQL Server

Erfahren Sie, welche Schritte zum Download des aktuellen Stands des Buchs "Access und SQL Server"... [mehr]

Bilder in Access 2013

Wer die Bibliothek mdlOGL0710 von Sascha Trowitzsch oder ein ähnliches Modul aus meinen... [mehr]

Dynamische Ribbons

Immer wieder fragen Leser, wie man Ribbon-Elemente wie etwa Schaltflächen in Abhängigkeit... [mehr]

Die Blogmaschine

Einen kleinen Blog zusätzlich zum Shop zu betreiben ist eine tolle Sache. Hier lassen sich... [mehr]

Wegwerfadressen für die Newsletteranmeldung

Die Verwendung von Wegwerf-Adressen für die Nutzung aller möglichen Online-Dienste nimmt... [mehr]

Access und Facebook

Facebook und Access - das ist eine der wenigen Kombinationen, die ich noch nicht in die Mangel... [mehr]

Access und SQL Server - das Projekt

Mein neues Buch Access und SQL Server (gemeinsam mit Bernd Jungbluth) geht in die Endphase. Wer... [mehr]