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

Nun muss die Prozedur noch die Inhalte des Anlagefelds in das OLE-Feld übertragen, und zwar für alle enthaltenen Datensätze. Dies erledigen die Befehle in der folgenden Do While-Schleife.

Diese lesen, vereinfacht beschrieben, den relevanten Inhalt des Anlage-Feldes aus, speichern diesen in einem Byte-Array und fügen dessen Inhalt mit der Methode AppendChunk in das OLE-Feld ein. Dass sich etwas getan hat, erkennen Sie in der Datenblattansicht der Tabelle, die für das Feld FileOLE nun jeweils den Text Long binary-Daten ausweist (siehe Bild 7). Wie aber prüfen Sie nun, ob der Inhalt korrekt dort gelandet ist Dazu verwenden Sie die Prozedur SaveOLEFieldToFile im Modul mdlOLE der Beispieldatenbank, mit dem Sie etwa den Inhalt des OLE-Feldes FileOLE des Datensatzes mit dem Wert 2 im Primärschlüsselfeld id unter dem Namen test.png im Verzeichnis der aktuellen Datenbank speichern:

pic007.png

Bild 7: Die Daten aus dem Anlagefeld wurden in ein OLE-Feld übertragen.

SaveOLEFieldToFile "MSysResources", "id", 2, "FileOLE", CurrentProject.Path & "\test.png"

Wenn Sie sich von der ordnungsgemäßen Übertragung der Dateien überzeugt haben, können Sie das Anlagefeld Data löschen (natürlich nicht, ohne zuvor eine Sicherheitskopie der kompletten Datenbank zu erstellen). Die Beispieldatenbank ist somit Anlagefeld-frei und ein erneuter Versuch des Exports in das Format Access 2002/2003 steht an.

Achtung: Wenn Sie die Tabelle MSysResources in eine .mdb-Datenbank importieren, wird das Feld Data in ein Memofeld umgewandelt.

Sie sollten dann die Prozedur File2OLE vor dem Import in der .accdb-Datei ausführen. Stellen Sie außerdem sicher, dass die Tabelle MSysResources nicht in Verwendung ist – dies erreichen Sie am zuverlässigsten, wenn Sie die Datenbank bei gedrückter Umschalttaste öffnen.

Wenn Sie weitere Anlagefelder verwenden

Sollten Sie in einer eigenen Datenbank, die nach Access 2002/2003 migriert werden soll, weitere Anlage-Felder nutzen, müssen Sie auch diese durch OLE-Felder ersetzen.

Dazu können Sie die in den Prozeduren DateienSpeichern und Anlage2OLE verwendeten Tabellen- und Feldnamen anpassen und die betroffenen Tabellen damit behandeln.

Neuer Export

Bei den Experimenten zu diesem Beitrag reagierte Access 2010 nicht wie gewohnt auf den Doppelklick auf die Schaltfläche zum Exportieren der Datenbank im Format von Access 2002/2003. Ein Öffnen und Schließen und Komprimieren ermöglichte dies jedoch im Anschluss wieder. Der Export erfolgte nun ohne Probleme, die Datei konnte unter dem Namen KVA.mdb gespeichert werden (s. Bild 8).

pic008.png

Bild 8: Speichern der Anwendung als .mdb-Datei

Datenbank in Access 2003 öffnen

Alle weiteren Versuche, die Datenbank auf den Einsatz unter Access 2003 vorzubereiten, sollten direkt in der Zielversion der Access-Anwendung geschehen. Wechseln Sie also zu einem anderen Rechner oder auch zu einer virtuellen Maschine, kopieren Sie die Dateien KVA.mdb und die Backenddatei KA_BE.mdb (die Sie zwischenzeitlich auch umgewandelt haben) dorthin und öffnen Sie die Anwendung.

Dies führt dazu, dass wie beim Original das in den Anwendungsoptionen festgelegte Formular frmStart geöffnet werden soll. Bevor dies geschieht, entdeckt VBA jedoch gleich einen Kompilierfehler: die Funktion Left könnte nicht gefunden werden (s. Bild 9). Kein Problem: Wer diesen Fehler, der auch mit weiteren VBA-Funktionen auftreten kann, einmal erlebt und behoben hat, weiß, wo der Hebel anzusetzen ist – und zwar in den Verweisen. Also klicken Sie auf OK, halten den Code mit dem Menüeintrag Ausführen|Zurücksetzen an und öffnen mit Extras|Verweise den Verweise-Dialog.

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