Vorbereitung

Vorbereitung zum Strukturupdate

Bevor Sie die Datenbank anpacken und updaten, sollten Sie sicher sein, dass nur ein Anwender, nämlich der, der das Update gerade aufruft, auf die Datenbank bzw. das Backend zugreift. Arbeiten mehrere Anwender mit der Datenbank kann entweder diese nicht modifiziert werden oder es kann zu Fehlern kommen. Für jede Datenbank legt die Jet-Engine, sobald die Datei (MDB/MDE) in Benutzung ist, eine LDB-Datei an. Die Datei trägt den gleichen Dateinamen wie die Datenbank. Anstatt der Endung MDB bzw. MDE ist hier das Präfix LDB. In dieser Datei speichert die Jet-Engine alle Benutzer und Hostnamen, die auf die Datenbank zugreifen. Mit den folgenden Codezeilen kann ermittelt werden, wie viele Anwender auf eine Datenbank zugreifen. Möchten Sie eine Strukturänderung durchführen, sollten Sie sicher sein, dass nicht mehr als ein Anwender auf diese Datenbank zugreift.

Zunächst wird ein neuer Datentyp angelegt. In diesen werden später die Informationen, die aus der LDB-Datei ausgelesen werden, abgelegt.

Private Type mtypLdbUserInfo
  Computername    As String * 32
  UserName        As String * 32
End Type

Die Funktion CheckUserCount liefert die Zahl der Anwender dieser Datenbank zurück, die sich in ihr befinden oder befanden. Es spielt dabei keine Rolle, ob der Anwender die Datenbank direkt geöffnet hat oder über „verknüpfte Tabellen“ darauf zugreift. Liefert die Funktion einen größeren Wert als 1 zurück, sollte kein Update erfolgen.

HinweisHinweis: Wenn ein User aus der DB rausgeht, so wird der entsprechende Eintrag in der LDB nicht gelöscht! Für den sicheren Vollzug der DB-Strukturänderungen reicht es unter Umständen, nur die Existenz der LDB abzufragen. Wenn sie nicht existiert, kann’s gemacht werden, wenn doch, dann nicht. (Auch wenn kein User in der DB ist, die LDB aber trotzdem existiert, z.B., weil Access abstürzte, sollten die Strukturänderungen nicht ablaufen, weil das ein Hinweis darauf sein könnte, dass die DB beschädigt ist oder zumindest erst mit CompactRepair behandelt werden sollte.)

Public Function CheckUserCount(ByVal psDBName As String) As Long
 
    Dim F           As Integer
    Dim lNUsers     As Long
    Dim lI          As Long
    Dim UserInfo    As mtypLdbUserInfo
 
    If LCase(Right(psDBName, 4)) = ".mdb" Then
        psDBName = Left(psDBName, Len(psDBName) - 4) + ".ldb"
    End If
 
    If CheckFile(psDBName) Then
        F = FreeFile
        Open psDBName For Random Shared As #F Len = Len(UserInfo)
        lNUsers = Int(LOF(F) / Len(UserInfo))
        Close #F
    End If
 
    CheckUserCount = lNUsers
 
End Function

In der Funktion CheckUserCount wird eine weitere Funktion CheckFile aufgerufen. Sie können diese Prüfung zwar beiseite lassen, aber es empfiehlt sich immer, alle Fehlerquellen abzuprüfen. Es kann sein, dass die Datenbank von einer CD exklusiv und schreibgeschützt geöffnet wurde. In diesem Fall wird keine LDB-Datei im Datenbankverzeichnis angelegt. Ohne Prüfung auf die existierende Datei würde ein Programm- bzw. Anwenderfehler auftreten.
Wenn man eine externe Datenbank modifiziert, sollte man auch prüfen, ob diese Datei existiert. Diese Prüfung kann man ebenfalls mit der Funktion CheckFile vornehmen.
Nachfolgend die Funktion zum Prüfen auf eine existierende Datei. Als Ergebnis wird True geliefert, wenn die Datei vorhanden ist. Wir die Datei nicht gefunden ist das Ergebnis False.

1. Möglichkeit über VBA
Public Function CheckFile(ByVal psFileName As String) As Boolean
 
    CheckFile = (Len(VBA.Dir(psFileName)) > 0)
 
End Function
2. Möglichkeit über API

Beispiel:

' Deklarationen und Typen
Const mclAXPATH         As Long = 260
 
Type gtypFILETIME
    dwLowDateTime       As Long
    dwHighDateTime      As Long
End Type
 
Type gtypWIN32_FIND_DATA
    dwFileAttributes    As Long
    ftCreationTime      As gtypFILETIME
    ftLastAccessTime    As gtypFILETIME
    ftLastWriteTime     As gtypFILETIME
    nFileSizeHigh       As Long
    nFileSizeLow        As Long
    dwReserved0         As Long
    dwReserved1         As Long
    cFileName           As String * mclAXPATH
    cAlternate          As String * 14
End Type
 
Declare Function FindFirstFile Lib "kernel32" Alias _
                               "FindFirstFileA" _
                               (ByVal lpFileName As String, _
                                lpFindFileData As gtypWIN32_FIND_DATA) _
                                As Long
 
Declare Function FindClose Lib "kernel32" _
                           (ByVal hFindFile As Long) _
                           As Long
 
Public Function APIFileExists(ByVal psSource As String) As Boolean
 
    Const clINVALID_HANDLE_VALUE As Long = -1
    Dim WFD As gtypWIN32_FIND_DATA
    Dim lFile As Long
 
    lFile = FindFirstFile(psSource, WFD)
    '// Prüfung auf gültigen Datei-Handle
    APIFileExists = lFile <> clINVALID_HANDLE_VALUE
    Call FindClose(lFile)
 
End Function
Existiert eine Tabelle

Zum Prüfen, ob eine Tabelle bereits existiert gehen Sie wie folgt vor:

1. Variante DAO
Public Function TableExistsDAO(pDb As DAO.Database, _
                               ByVal psName As String) _
                               As Boolean
 
    Dim s As String
 
    On Error Resume Next
    s = pDb.TableDefs(psName).Name
    TableExistsDAO = (Err.Number = 0)
 
End Function
2. Variante ADOX
Public Function TableExistsADOX(pcnn As ADODB.Connection, _
                                ByVal psName As String) _
                                As Boolean
 
    Dim s As String
    Dim cat As New ADOX.Catalog
 
    On Error Resume Next
    cat.ActiveConnection = pcnn
    s = cat.Tables(psName).Name
    TableExistsADOX = (Err.Number = 0)
    If Not cat Is Nothing Then Set cat = Nothing
 
End Function