Anlagefelder mit mehreren Dateien zum SQL Server

Im Beitrag „Anlage-Feld zum SQL Server migrieren“ (www.access-im-unternehmen.de/1542) haben wir gezeigt, wir man die Inhalte von Anlagefeldern einer Access-Datenbank in ein varbinary(max)-Feld einer SQL Server-Datenbank übertragen können. Dort sind wie davon ausgegangen, dass jedes Anlagefeld immer nur eine Datei enthält, was in vielen Fällen ausreichend ist. Was aber, wenn der Entwickler das Anlagefeld für mehrere Dateien vorgesehen hat – beispielsweise, um ein oder mehrere Produktbilder zu einem Produkt zu speichern? In diesem Fall müssen wir umdenken, den wir können optimalerweise immer nur eine Datei in einem varbinary(max)-Feld speichern. Zum Speichern mehrerer Dateien müssen wir uns also einen Workaround überlegen. Wie dieser aussieht, schauen wir uns im vorliegenden Beitrag an.

Anlagefelder mit einem oder mehreren Dateien

Anlagefelder speichern ihre Anlagen in einer internen Tabelle, die von außen erst einmal nicht sichtbar ist. Deshalb ist es auch möglich, dass für einen einzelnen Datensatz mehr als eine Anlage hinterlegt werden können.

Im Beispiel verwenden wir die Tabelle tblProdukte, die in der Entwurfsansicht wie in Bild 1 aussieht.

Tabelle zum Speichern von Produkten mit Bildern

Bild 1: Tabelle zum Speichern von Produkten mit Bildern

In der Datenblattansicht haben wir der Tabelle drei Bilder zum Anlagefeld hinzugefügt (siehe Bild 2).

Tabelle mit mehreren Anlagen

Bild 2: Tabelle mit mehreren Anlagen

Dass es in einem Anlagefeld ein Objekt wie eine Tabelle geben muss, sehen wir, wenn wir eine Tabelle mit einem Anlagefeld in eine neue, leere Abfrage ziehen. Hier fügen wir einmal alle Felder der Tabelle einschließlich der Felder des Anlagefeldes zum Entwurfsraster hinzu (siehe Bild 3).

Die Untertabelle in einem Anlagefeld

Bild 3: Die Untertabelle in einem Anlagefeld

Wechseln wir hier in die Datenblattansicht, sehen wir, dass die Idee, dass wir es hier mit einer internen Untertabelle zu tun haben, nicht allzu abwegig ist. Aus dem einen Datensatz werden nun direkt drei Datensätze, was sonst nur geschieht, wenn wir eine verknüpfte Tabelle mit in den Abfrageentwurf ziehen (siehe Bild 4).

Die Felder eines Anlagefeldes in der Datenblattansicht

Bild 4: Die Felder eines Anlagefeldes in der Datenblattansicht

Anlagen mit mehreren Dateien zum SQL Server migrieren

Betrachten wir nun die Aufgabe, die Inhalte einer solchen in eine SQL Server-Datenbank zu übertragen, sehen wir erst einmal kein derartiges Konstrukt, indem wir mehrere Datensätze pro Feld speichern könnten.

Letztlich ist das, was wir hier abgebildet sehen, nichts anderes als zwei Tabellen, die per 1:n-Beziehung miteinander verknüpft sind. Und das lässt sich wiederum auch im SQL Server abbilden – wenn auch mit Unterstützung durch eine weitere Tabelle.

Wir erstellen also im SQL Server zwei Tabellen, um die Daten dieser einen Tabelle mit Anlagefeld abzubilden. Diese sehen wie folgt aus:

  • tblProdukte: ProduktID (Primärschüsselfeld), Produkt (Textfeld)
  • tblProduktbilder: ProduktbildID (Primärschlüsselfeld), ProduktID (Fremdschlüsselfeld zur Tabelle tblProduktbilder), Produktbild (Datentyp varbinary(max))

Um die Tabellen schnell zu erstellen, können wir das folgende Skript nutzen:

CREATE TABLE tblProdukte (    ProduktID INT IDENTITY(1,1) PRIMARY KEY,    Produkt NVARCHAR(255) NOT NULL);CREATE TABLE tblProduktbilder (    ProduktbildID INT IDENTITY(1,1) PRIMARY KEY,    ProduktID INT NOT NULL,    Produktbild VARBINARY(MAX) NOT NULL,    CONSTRAINT FK_Produktbilder_Produkte         FOREIGN KEY (ProduktID)         REFERENCES tblProdukte (ProduktID)             ON DELETE CASCADE);

Danach können wir uns an die Erstellung des Code zum Übertragen der Daten samt Bilddaten begeben.

Notwendiger Parameter zum Übertragen der Tabelle inklusive Anlagefeld

Im Beitrag Anlage-Feld zum SQL Server migrieren (www.access-im-unternehmen.de/1542) haben wir bereits eine ähnliche Funktion programmiert, die wir komplett über Parameter steuern können. Im vorliegenden Beitrag benötigen wie eine ähnliche Prozedur, die allerdings noch einige weitere Parameter benötigt. Immerhin sollen die Daten aus ursprünglich einer Tabelle nun auf zwei Tabellen aufgeteilt werden.

Zuvor legen wir fest, wie wir hier vorgehen wollen. Wollen wir eine ähnliche Prozedur schreiben, wie wir sie im oben genannten Beitrag angelegt haben, die für eine bereits bestehende Migration inklusive Daten nur noch die Inhalte der Anlagefelder hinterherkopiert? Dies ist in den Fällen interessant, wo man die übrige Migration bereits vollständig durchgeführt hat, beispielsweise mit einem Tool wie SQL Server Migration Assistant.

In diesem Beitrag wollen wir jedoch eine Lösung kreieren, welche die Inhalte der Tabellen vollständig überträgt.

Wir gehen also von den leeren Tabellen tblProdukte und tblProduktbilder auf dem SQL Server aus und wollen alle enthaltenen Informationen dorthin übertragen.

Wir werden also in den folgenden Schritten vorgehen:

  • Übertragen eines Datensatzes der Tabelle tblProdukte zur gleichnamigen SQL Server-Tabelle (mit Ausnahme des Anlagefeldes)
  • Merken des neuen Primärschlüsselwertes
  • Durchlaufen der Anlagen und schrittweises Übertragen der Anlagen in die Tabelle tblProdukteBilder, wobei wir den gemerkten Primärschlüsselwert als Fremdschlüsselwert nutzen

Für die Parametrisierung benötigen wir also die folgenden Daten:

  • strAccessTable: Name der Haupttabelle
  • strAccessField: Name des Anlagefeldes der Haupttabelle
  • strAccessPKField: Name des Primärschlüsselfeldes der Haupttabelle
  • lngAccessPKID: Wert des Primärschlüsselfeldes des aktuellen Datensatzes
  • strSQLTable: Name der Haupttabelle im SQL Server
  • strSQLPKField: Name des Primärschlüsselfeldes der Haupttabelle im SQL Server
  • strSQLAttachmentTable: Name der Anlagentabelle im SQL Server
  • strSQLAttachmentPKField: Name des Primärschlüsselfeldes der Anlagentabelle im SQL Server
  • strSQLVarBinaryMaxField: Name des varbinary(max)-Feldes in der Anlagentabelle im SQL Server
  • strSQLAttachmentFKField: Name des Fremdschlüsselfeldes der Anlagentabelle im SQL Server
  • cnn: Verbindung zum SQL Server
  • db: Verweis auf das aktuelle Database-Objekt
  • strErrorMessage: Rückgabeparameter für Fehlermeldungen

Aufruf der Funktionen

Den Start machen wir mit der Prozedur TabelleMitMehrfachanlagenZumSQLServer (siehe Listing 1). Diese erstellt einen Verweis auf das aktuelle Database-Objekt sowie eine Connection auf die entsprechende SQL Server-Datenbank.

Public Sub TabelleMitMehrfachanlagenZumSQLServer()
     Dim db As DAO.Database
     Dim cnn As ADODB.Connection
     Dim rst As DAO.Recordset
     Dim strErrorMessage As String
     Dim strSQL As String
     Dim cmd As ADODB.Command
     Dim rstResult As ADODB.Recordset
     Dim lngID As Long
     Dim bolKopiert As Boolean
     Set db = CurrentDb
     Set cnn = New ADODB.Connection
     cnn.Open cStrConnection
     Set rst = db.OpenRecordset("SELECT * FROM tblProdukte", dbOpenDynaset)
     Do While Not rst.EOF
         strSQL = "INSERT INTO tblProdukte(Produkt) OUTPUT INSERTED.ProduktID  VALUES(''" & rst!Produkt & "'');"
         Set cmd = New ADODB.Command
         cmd.ActiveConnection = cnn
         cmd.CommandText = strSQL
         cmd.CommandType = adCmdText
         Set rstResult = cmd.Execute()
         If Not rstResult.EOF Then
             lngID = rstResult!ProduktID
             bolKopiert = CopyAttachmentToVarBinaryMax_Multi("tblProdukte", "Produktbilder", "ProduktID", _
                 rst!ProduktID, lngID, "tblProduktbilder", "Produktbild", "ProduktID", cnn, db, strErrorMessage)
             If bolKopiert = True Then
                 MsgBox "Datensatz " & rst!ProduktID & " erfolgreich kopiert."
             Else
                 MsgBox "Datensatz " & rst!ProduktID & " nicht kopiert." & vbCrLf & vbCrLf & strErrorMessage, _
                     vbCritical + vbOKOnly, "Fehler beim Kopieren"
             End If
         End If
         rst.MoveNext
     Loop
     rst.Close
     Set rst = Nothing
     Set db = Nothing
     cnn.Close
     Set cnn = Nothing
End Sub

Listing 1: Aufruf der Funktionen zum Kopieren von Tabellen mit Anlagefeldern mit mehreren Dateien

Die dafür notwendige Verbindungszeichenfolge haben wir in diesem Fall wie folgt in einer Konstanten hinterlegt:

Public Const cStrConnection As String = "Provider=MSOLEDBSQL;Data Source=amvdesktop2023;Initial Catalog=Anlagen;Integrated Security=SSPI;"

Die Verbindung öffnet die Prozedur dann mit der Open-Methode. Außerdem füllen wir ein Recordset mit den Datensätze der Tabelle tblProdukte und durchlaufen dieses in einer Do While-Schleife über alle Datensätze.

Darin kopieren wir zunächst die Daten dieser Tabelle mit Ausnahme des Anlagefeldes. Dazu erstellen wir eine entsprechende INSERT INTO-Anweisung. Diese wollen wir mithilfe eines Command-Objekts ausführen, dem wir die Verbindung aus cnn zuweisen und für das wir die INSERT INTO-Anweisung als CommandText hinterlegen.

Die INSERT INTO-Anweisung hat die Besonderheit, dass wir in ihr mit OUTPUT INSERTED.ProduktID direkt den Primärschlüsselwert des neu erstellten Datensatzes ermitteln. Um diesen später auszulesen, speichern wir das Ergebnis der Execute-Methode in einem Recordset namens rstResults.

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