Microsoft Access ist ein vielgenutztes Produkt in zahlreichen Unternehmen aller Branchen. Dies liegt darin begründet, dass das Microsoft-Office-Paket weit verbreitet ist, und die ,Access-Lösung' somit überall vorhanden.
Leider hat diese Lösung auch Nachteile. Diese machen sich bemerkbar, wenn mann ein Access-Frontend für eine Datenbankanbindung realisiert. Einer dieser Nachteile ist die fehlende Möglichkeit, Transaktionen zu realisieren oder auf Stored Procedures sowie Table-Functions zurückzugreifen.
Über die Access-Oberfläche allein ist dies auch so nicht möglich. Es gibt zwar einen SQL-Pass-Through, um DBMS-proprietäre SQL-Abfragen auszuführen, jedoch sind diese oftmals nur statisch möglich und müssen angepasst werden.
Visual Basic for Applications (kurz VBA) kann hier eine gewisse Abhilfe schaffen. So ist es z. B. möglich, den Button-Steuerelementen eines Access-Formulars VBA-Makros (Subs) zuzuweisen, und diese beim Klicken auszuführen. Ereignisse wie dieses OnClick-Ereignis können jedoch nicht nur für das Klicken eines Buttons implementiert werden. Ferner existieren über ein Dutzend solcher Ereignisse, auf die VBA reagieren kann. Beispielsweise kann ein Ereignis behandelt werden, wenn das Formular geöffnet, aktiviert oder geschlossen wird.
Weiterhin ist es möglich, über die Access-Database-API auf den Workspace zuzugreifen und eine Transaktion zu starten, um später über einen Button eine dynamische Pass-Through-Abfrage abzusetzten und erst danach ein Commit oder Rollback durchzuführen. Es werden folgende Steuerelemente beötigt:
Für das Form_Open-Ereignis genügt bereits eine Zeile, um die Transaktion zu beginnen:
Passend dazu muss man die Transaktion nun mit Commit in einem OnClick-Ereignis beenden:
Oder mittels Rollback verwerfen:
Bis hier waren alles einfache und übersichtliche Einzeiler; etwas aufwendiger wird es nun, die Daten in die Datenbank einzufügen. Denn die normalen Access-Funktionen committen sofort, dies kann auch mit den vorherigen VBA-Statements nicht außer Kraft gesetzt werden. Stattdessen muss man nun Formular-Felder verwenden, die NICHT mit den Attributen einer Tabelle verknüpft sind. Sie müssen lediglich eindeutige Namen Besitzen:
Hinweis: Da hier mit einer Stored Procedure gearbeitet wird, werden zwei Datumswerte durch einen String im Format 'TT.MM.YYYY' übergeben (EdGeburt, EdMember). Der Code für den Button den Aufruf der Prozedur, die den Datensatz einfügt:
Wenn man nun das Formular öffnet, wird die Transaktion durch das Form_Open-Ereignis begonnen. Die Werte werden nun in die Textfelder eingefügt und ein Klick auf den Insert-Button führt für die lokale Oracle-Session ein Insert durch. Öffnet man nun eine zweite Session und schaut sich den Datenbestand an, so wird man keine Änderungen erkennen.
Nun klickt man den Button Cut_Commit. Eine zweite Abfrage der Daten über die zweite Session lässt erkennen, dass der Bestand sich nun geändert hat - die Transaktion war erfolgreich.
Als Verbesserung arbeite ich noch an Prepared Statements. Allerdings endeten bisher alle Versuche in Fehlern.
Leider hat diese Lösung auch Nachteile. Diese machen sich bemerkbar, wenn mann ein Access-Frontend für eine Datenbankanbindung realisiert. Einer dieser Nachteile ist die fehlende Möglichkeit, Transaktionen zu realisieren oder auf Stored Procedures sowie Table-Functions zurückzugreifen.
Über die Access-Oberfläche allein ist dies auch so nicht möglich. Es gibt zwar einen SQL-Pass-Through, um DBMS-proprietäre SQL-Abfragen auszuführen, jedoch sind diese oftmals nur statisch möglich und müssen angepasst werden.
Visual Basic for Applications (kurz VBA) kann hier eine gewisse Abhilfe schaffen. So ist es z. B. möglich, den Button-Steuerelementen eines Access-Formulars VBA-Makros (Subs) zuzuweisen, und diese beim Klicken auszuführen. Ereignisse wie dieses OnClick-Ereignis können jedoch nicht nur für das Klicken eines Buttons implementiert werden. Ferner existieren über ein Dutzend solcher Ereignisse, auf die VBA reagieren kann. Beispielsweise kann ein Ereignis behandelt werden, wenn das Formular geöffnet, aktiviert oder geschlossen wird.
Weiterhin ist es möglich, über die Access-Database-API auf den Workspace zuzugreifen und eine Transaktion zu starten, um später über einen Button eine dynamische Pass-Through-Abfrage abzusetzten und erst danach ein Commit oder Rollback durchzuführen. Es werden folgende Steuerelemente beötigt:
Typ: Name:
Button But_Commit
Button But_Rollback
Button But_Commit
Button But_Rollback
Für das Form_Open-Ereignis genügt bereits eine Zeile, um die Transaktion zu beginnen:
Private Sub Form_Open(Cancel As Integer)
' initialize a transaction
DBEngine.BeginTrans
End Sub
' initialize a transaction
DBEngine.BeginTrans
End Sub
Passend dazu muss man die Transaktion nun mit Commit in einem OnClick-Ereignis beenden:
Private Sub But_Commit_Click()
' commit transaction
DBEngine.CommitTrans
End Sub
' commit transaction
DBEngine.CommitTrans
End Sub
Oder mittels Rollback verwerfen:
Private Sub But_RollBack_Click()
' rollback the transaction
DBEngine.Rollback
End Sub
' rollback the transaction
DBEngine.Rollback
End Sub
Bis hier waren alles einfache und übersichtliche Einzeiler; etwas aufwendiger wird es nun, die Daten in die Datenbank einzufügen. Denn die normalen Access-Funktionen committen sofort, dies kann auch mit den vorherigen VBA-Statements nicht außer Kraft gesetzt werden. Stattdessen muss man nun Formular-Felder verwenden, die NICHT mit den Attributen einer Tabelle verknüpft sind. Sie müssen lediglich eindeutige Namen Besitzen:
Typ: Name:
Button But_Insert
Button But_Insert
Textfeld EdVorname
Textfeld EdNachname
Textfeld EdGeburt
Textfeld EdMember
Hinweis: Da hier mit einer Stored Procedure gearbeitet wird, werden zwei Datumswerte durch einen String im Format 'TT.MM.YYYY' übergeben (EdGeburt, EdMember). Der Code für den Button den Aufruf der Prozedur, die den Datensatz einfügt:
Private Sub But_Insert_Click()
Dim ParamString As String
Dim LSProc As QueryDef
' enable error handling
On Error GoTo 0
' create parameters without parameter binding
ParamString = "'" + Forms(thisForm).Controls("EdVorname").Value + "',"
ParamString = ParamString + "'" + Forms(thisForm).Controls("EdNachname").Value + "',"
ParamString = ParamString + "'" + Format(Forms(thisForm).Controls("EdGeburt").Value, "dd.mm.yyyy") + "',"
ParamString = ParamString + "'" + Format(Forms(thisForm).Controls("EdMember").Value, "dd.mm.yyyy") + "'"
' create a querydef fpr global database var gDAODB
Set LSProc = CurrentDb.CreateQueryDef("")
'specify the connection manually
LSProc.Connect = "ODBC;DSN=SLIGO_FH-TRIER"
LSProc.SQL = "begin banking.insert_kunde(" + ParamString + "); end;"
' we don't expect any output
LSProc.ReturnsRecords = False
' we ignore the timeout
LSProc.ODBCTimeout = 0
LSProc.Execute
End Sub
Dim ParamString As String
Dim LSProc As QueryDef
' enable error handling
On Error GoTo 0
' create parameters without parameter binding
ParamString = "'" + Forms(thisForm).Controls("EdVorname").Value + "',"
ParamString = ParamString + "'" + Forms(thisForm).Controls("EdNachname").Value + "',"
ParamString = ParamString + "'" + Format(Forms(thisForm).Controls("EdGeburt").Value, "dd.mm.yyyy") + "',"
ParamString = ParamString + "'" + Format(Forms(thisForm).Controls("EdMember").Value, "dd.mm.yyyy") + "'"
' create a querydef fpr global database var gDAODB
Set LSProc = CurrentDb.CreateQueryDef("")
'specify the connection manually
LSProc.Connect = "ODBC;DSN=SLIGO_FH-TRIER"
LSProc.SQL = "begin banking.insert_kunde(" + ParamString + "); end;"
' we don't expect any output
LSProc.ReturnsRecords = False
' we ignore the timeout
LSProc.ODBCTimeout = 0
LSProc.Execute
End Sub
Wenn man nun das Formular öffnet, wird die Transaktion durch das Form_Open-Ereignis begonnen. Die Werte werden nun in die Textfelder eingefügt und ein Klick auf den Insert-Button führt für die lokale Oracle-Session ein Insert durch. Öffnet man nun eine zweite Session und schaut sich den Datenbestand an, so wird man keine Änderungen erkennen.
Nun klickt man den Button Cut_Commit. Eine zweite Abfrage der Daten über die zweite Session lässt erkennen, dass der Bestand sich nun geändert hat - die Transaktion war erfolgreich.
Als Verbesserung arbeite ich noch an Prepared Statements. Allerdings endeten bisher alle Versuche in Fehlern.
Kommentare
Kommentar veröffentlichen