ACCDB nach Access 2003 migrieren

Kennen Sie das auch Sie haben eine schicke Datenbank mit Access 2007 oder 2010 erstellt, diese mit einem Ribbon und Schaltflächen mit Icons ausgestattet und nun kommt ein Kunde und möchte diese Datenbank unter Access 2003 einsetzen. Da kommt schon ein wenig Aufwand auf Sie zu! Deshalb nehmen wir ein solches Downgrade im vorliegenden Beitrag einmal unter die Lupe.

Ausgangspunkt ist die Datenbank KVA.accdb aus dem Beitrag Kunden, Verträge und Anschreiben verwalten (www.access-im-unternehmen.de/854). Diese Anwendung wurde sogar unter Access 2010 erstellt und soll nun, soweit möglich, unter Access 2003 lauffähig gemacht werden. Damit dies gelingt, muss die Anwendung zunächst einmal um solche Elemente erleichtert werden, die sogar ein Speichern im Format von Access 2002/2003 unmöglich machen.

Ob die Datenbank solche Elemente enthält, finden Sie etwa unter Access 2010 heraus, indem Sie auf Datei klicken, dann im Backstage-Bereich auf Speichern und Veröffentlichen und schließlich auf Access 2002-2003-Datenbank (*.mdb) – s. Bild 1. Entweder führen Sie hier einen Doppelklick aus oder Sie betätigen nach der Auswahl die Schaltfläche Speichern unter.

pic001.png

Bild 1: Speichern einer Datenbank im Format von Access 2002/2003

Unter Access 2007 verwenden Sie dazu den Eintrag Speichern unter|Access 2002 – 2003-Datenbank des Office-Menüs (s. Bild 2).

pic002.png

Bild 2: Datenbank von Access 2007 aus in anderen Formaten speichern

Tendenziell enthält eine Datenbank unter Access 2007 oder 2010 Elemente, die unter Access 2002/2003 noch nicht bekannt waren.

Ist dies der Fall, meldet Access den Fehler aus Bild 3. Hier werden gleich einige potenzielle Probleme genannt – unter Access 2007 etwa Anlagefelder oder mehrwertige Felder; unter Access 2010 kommen noch Elemente wie Datenmakros, neue Verschlüsselungstypen oder Navigationssteuerelemente hinzu.

pic003.png

Bild 3: Fehlermeldung beim Versuch, eine Datenbank mit reinen Access 2007/2010-Features in eine ältere Version umzuwandeln

Während Sie relativ sicher sein können, dass wir in Access im Unternehmen keine mehrwertigen Felder einsetzen, so sieht dies bei Anlagefeldern anders aus: Wenn Sie mit Access 2010 arbeiten und etwa Bilder in Schaltflächen darstellen möchten, kommen Sie nicht um den Einsatz einer Systemtabelle namens MSysResources herum (die standardmäßig ausgeblendet ist – machen Sie diese unter Access 2010 durch die Aktivierung der Optionen Ausgeblendete Objekte anzeigen und Systemobjekte anzeigen sichtbar), die wiederum Bilder in einem Anlagefeld speichert.

Diese Bilddateien können so bequem als Bilder für Bildsteuerelemente oder Schaltflächen ausgewählt werden.

Sollte diese Meldung erscheinen, beginnt die Arbeit also gleich in der Access-Version, mit der Sie die Anwendung erstellt haben. Sie müssen hier die Tabellen ausfindig machen, die Felder vom Typ Anlage enthalten.

Je nachdem, wie lange Sie die Anwendung bereits entwickeln und wie umfangreich diese geworden ist, haben Sie möglicherweise keinen Überblick mehr, wo sich die Felder mit dem betreffenden Datentyp befinden.

Wollen Sie nun alle Tabellen manuell durchsuchen oder lieber einen kleinen Codeschnipsel programmieren, der alle Anlage-Felder (und gegebenenfalls auch die mehrwertigen Felder) ausgibt Wir entscheiden uns natürlich für letztere Variante, da diese auch zuverlässiger arbeiten dürfte.

Wechseln Sie also zum VBA-Editor und legen Sie in einem geeigneten Modul, beispielsweise mdlTools, eine neue Prozedur namens NeueDatentypenFinden an. Grundsätzlich soll die Prozedur alle Tabellen und alle darin enthaltenen Felder durchlaufen und die Datentypen auf die neuen Typen prüfen.

Die Type-Eigenschaft eines Field-Elements eines TableDef-Elements liefert aber Zahlenwerte. Und wo erhalten wir Informationen über die Konstanten zu diesen Zahlenwerten Im Objektkatalog. Diesen öffnen Sie mit der Taste F2 und suchen nach dem Begriff Enum.

Darunter finden Sie dann alle möglichen Enumerationen wie DatabaseTypeEnum, FieldAttributeEnum oder auch die gesuchte DataTypeEnum. Klicken Sie auf DataTypeEnum, zeigt der Objektkatalog wie in Bild 4 die verfügbaren Datentypen samt Zahlenwert an.

pic004.png

Bild 4: Objektkatalog mit Felddatentypen

Die neuen Datentypen sind mit Zahlenwerten größer 100 versehen – dbAttachment hat etwa den Wert 101. Also soll die Prozedur einfach alle Feldnamen ausgeben, deren Felddatentyp einen Zahlenwert größer als 100 aufweist:

Public Sub NeueFelddatentypenFinden()
    Dim db As DAO.Database
    Dim tdf As DAO.TableDef
    Dim fld As DAO.Field
    Set db = CurrentDb
    For Each tdf In db.TableDefs
         For Each fld In tdf.Fields
            If fld.Type > 100 Then
                Debug.Print tdf.Name, fld.Name, fld.Type
            End If
        Next fld
    Next tdf
    Set db = Nothing
End Sub

Die Prozedur durchläuft nun alle Tabellen (also TableDef-Objekte) der TableDefs-Auflistung der Datenbank und für jede Tabelle alle Felder (also Field-Objekte) der Fields-Auflistung der aktuellen Tabelle. Weist die Type-Eigenschaft einen Wert größer als 100 auf, gibt die Prozedur Tabellenname, Feldname und Datentyp im Direktfenster aus.

Bei der Beispieldatenbank kommen wir glimpflich davon: Das einzige Anlagefeld heißt Data und stammt aus der bereits erwähnten Tabelle MSysResources:

MSysResources Data 101

Im Beispiel der Datenbank KVA.accdb ist allerdings möglicherweise eine zusätzliche Untersuchung notwendig: Die Anwendung verwendet ja ein Backend, in dem sich auch noch Tabellen befinden.

Auch diese müssen Sie selbstverständlich nach entsprechenden neuen Felddatentypen untersuchen. Diese Aufgabe nimmt uns die obige Prozedur jedoch bereits ab: Sie greift auch auf die per Verknüpfung eingebundenen Tabellen zu und untersucht deren Felddatentypen.

Behandlung von Anlage-Feldern

Da wir in Access 2002/2003 ohnehin nicht auf Daten in Anlagefeldern zugreifen können, wäre es am einfachsten, diese Tabelle direkt zu löschen. Allerdings kann es ja sein, dass wir die enthaltenen Bilder noch für Menü- und Symbolleisten oder für Kontextmenüs benötigen. Nun gibt es drei Möglichkeiten:

  • Sie verfügen über eine Kopie der Bilddateien im Dateisystem und können diese später wieder in die Access 2002/2003-Version Ihrer Anwendung einbinden,
  • Sie speichern alle Bilder dieser Tabelle in das Dateisystem, um diese später wieder einzubinden, oder
  • Sie übertragen die Bilder gleich in eine ähnliche aufgebaute Tabelle, welche die Bilder allerdings in einem OLE-Feld speichert.

Die erste Variante erfordert keinen Aufwand. Die zweite können Sie je nach der Anzahl der Bilder manuell durchführen oder Sie verwenden auch hier eine Prozedur, um die Bilder auf die Festplatte zu bannen. Dazu vewenden Sie die Prozedur aus Listing 1. Diese liest zunächst die drei Felder Data.Filedata, Name und Extension aus der Tabelle MSysResources ein.

Listing 1: Dateien aus MSysResources speichern

Public Function DateienSpeichern()
    Dim rst As DAO.Recordset2
    Dim strFilename As String
    On Error GoTo Fehler
    Set rst = CurrentDb.OpenRecordset("SELECT Data.Filedata, Name, Extension FROM MSysResources", _
        dbOpenSnapshot)
    Do While Not rst.EOF
        strFilename = CurrentProject.Path & "\" & rst!Name & "." & rst!Extension
        If Dir(strFilename) <> "" Then
            Kill strFilename
            DoEvents
        End If
        On Error Resume Next
        rst("Data.Filedata").SaveToFile strFilename
        If Err.Number = (-2146697202) Then
            rst!Data.SaveToFile strFilename & ".dat"
            DoEvents
            Name strFilename & ".dat" As strFilename
        End If
        rst.MoveNext
    Loop
Ende:
    On Error Resume Next
    Set rst = Nothing
    Exit Function
Fehler:
    MsgBox Err.Number & "/" & Err.Description, vbCritical
    Resume Ende
End Function

Dabei bezieht sich Data.Filedata direkt auf das Feld Filedata der intern im Anlagefeld Data gespeicherten Untertabelle. Dies verdeutlicht eine Abfrage auf Basis der Tabelle MSysResources in der Entwurfsansicht (s. Bild 5).

pic005.png

Bild 5: Zugriff auf die Felder eines Attachment-Felds

Wir gehen an dieser Stelle davon aus, dass jeder Datensatz der Tabelle MSysResources immer nur mit einer Datei befüllt wurde. Dazu durchläuft die Prozedur alle Datensätze dieser Tabelle in einer Do While-Schleife. Innerhalb dieser Schleife ermittelt die Prozedur zunächst den Dateinamen aus den beiden Feldern Name und Extension.

Die Dateien sollen im Verzeichnis der Datenbank gespeichert werden. Dabei prüft die Prozedur, ob eine Datei gleichen Namens bereits vorhanden ist, und löscht diese gegebenenfalls zuvor.

Dabei kommt die Dir-Funktion zum Einsatz, die eine leere Zeichenkette zurückliefert, wenn die als Parameter angegebene Datei nicht vorhanden ist.

Dann versucht die Prozedur, die im Feld Data.Filedata enthaltene Datei mit der SaveToFile-Methode unter dem in strFilename enthaltenen Dateinamen zu speichern.

Gelingt dies nicht, liegt dies in der Regel daran, dass Access Sicherheitsbedenken wegen des Dateityps hat.

Dies erkennt Access allein an der Dateiendung, weshalb die Prozedur in diesem Fall einfach die erlaubte Dateiendung .dat anhängt, die Datei speichert und dann die Dateiendung wieder entfernt.

Dieser Vorgang wird für jeden Datensatz wiederholt, was eine mehr oder weniger große Menge Dateien in das Verzeichnis der aktuellen Datenbank spült.

Wenn Sie die Dateien in einem anderen Verzeichnis speichern möchten, ändern Sie einfach die Zeile

strFilename = CurrentProject.Path & "\" & rst!Name & "." & rst!Extension

ab, indem Sie hinter "\" ein Unterverzeichnis anhängen – zum Beispiel so:

strFilename = CurrentProject.Path & "\pics\" & rst!Name & "." & rst!Extension

Auf diese Weise werden die Bilder in einem Unterverzeichnis namens pics gespeichert, welches zuvor noch erzeugt werden muss – beispielsweise so (gleich hinter der Zeile Dim strFilename …):

On Error Resume Next
MkDir CurrentProject.Path & "\pics\"

Mit On Error Resume Next verhindern Sie, dass ein eventuell vorhandenes Verzeichnis gleichen Namens einen Fehler auslöst.

Vom Anlage-Feld zum OLE-Feld

Wenn Sie die im Anlagefeld gespeicherten Bilder und weitere Dateien anderweitig von der nach Access 2002/2003 migrierten Anwendung aus nutzen möchten und diese in einem Feld einer Tabelle speichern wollen, müssen Sie diese in einem OLE-Feld unterbringen.

Da die Tabelle MSysResources bereits vorhanden ist, können Sie diese gleich weiterverwenden: Dazu müssen Sie der Tabelle lediglich ein neues OLE-Feld etwa namens FileOLE hinzufügen und die Daten für jeden Datensatz aus dem Anlagefeld Data.Filedata in das OLE-Feld übertragen.

Das ist manuell gar nicht zu erledigen, sodass wir hier auf jeden Fall eine entsprechende VBA-Routine benötigen. Diese sieht wie in Listing 2 aus.

Listing 2: Inhalt vom Anlagefeld in ein OLE-Feld übertragen

Public Function Anlage2OLE()
    Dim db As DAO.Database
    Dim tdf As DAO.TableDef
    Dim fld As DAO.Field
    Dim rst As DAO.Recordset
    Dim bintmp() As Byte, bintmp2() As Byte
    Dim lOffset As Long
    Dim buffer() As Byte
    Set db = CurrentDb
    Set tdf = db.TableDefs("MSysResources")
    On Error Resume Next
    Set fld = tdf.Fields("FileOLE")
    If fld Is Nothing Then
        Set fld = tdf.CreateField("FileOLE", dbLongBinary)
        tdf.Fields.Append fld
    End If
    On Error GoTo 0
    Set rst = db.OpenRecordset("SELECT Data.Filedata, FileOle FROM MSysResources", dbOpenDynaset)
    Do While Not rst.EOF
        bintmp = rst(0).Value
        lOffset = bintmp(0)
        ReDim bintmp2(UBound(bintmp) - lOffset)
        CopyMemory bintmp2(0), bintmp(lOffset), UBound(bintmp2)
        buffer = bintmp2
        rst.Edit
        rst!FileOLE.AppendChunk buffer
        rst.Update
        rst.MoveNext
    Loop
    Erase bintmp
    Erase bintmp2
    Set tdf = Nothing
    Set db = Nothing
End Function

Die Prozedur prüft zunächst, ob die Tabelle bereits ein Feld namens FileOLE enthält – gegebenenfalls führen Sie diese Prozedur ja mehrfach aus, was bei Vorhandensein dieses Feldes einen Fehler bei der Neuanlage auslösen würde. Die Prozedur versucht also, eine Referenz auf das Feld in der Variablen fld zu speichern.

Da dies beim Fehlen des Feldes zu einem Fehler führt, wird die Fehlerbehandlung zuvor mit On Error Resume Next ausgeschaltet. Befindet sich anschließend ein Objektverweis in der Variablen (fld ist nicht Nothing), erstellt die Prozedur mit der Methode Add der Fields-Auflistung des TableDef-Objekts zur Tabelle MSysResources dieses Feld mit dem Typ dbLongBinary, was dem Felddatentyp OLE-Objekt entspricht. Die Tabelle sieht anschließend wie in Bild 6 aus.

pic006.png

Bild 6: MSysResources mit neuem OLE-Feld

Sie haben das Ende des frei verfügbaren Textes erreicht. Möchten Sie ...

TestzugangOder bist Du bereits Abonnent? Dann logge Dich gleich hier ein. Die Zugangsdaten findest Du entweder in der aktuellen Print-Ausgabe auf Seite U2 oder beim Online-Abo in der E-Mail, die Du als Abonnent regelmäßig erhältst:

Schreibe einen Kommentar