Announcement

Collapse
No announcement yet.

ADO und BLOB per ODBC

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • ADO und BLOB per ODBC

    Hallo,
    ich versuche per ADO (ODBC Provider) BLOBs in eine Datenbank zu schieben, was nicht funktioniert.
    Der ODBC treiber kann es nicht sein, da lesen über ADO bzw. schreiben über dbExpress funktioniert.

  • #2
    Hallo,

    ADO 2.5 hat zusätzlich zum Record-Objekt das <b>Stream</b>-Objekt in das ADO-Objektmodell eingeführt. Mit diesem Objekt vereinfacht sich der Zugriff auf BLOb-Daten (Binary Large Objects), da das Hantieren mit den alten Methoden GetChunk und AppendChunk nicht mehr notwendig ist. Mit dem neuen Objekt ist auch das vorherige Bestimmen der BLOb-Grösse nicht mehr notwendig, so dass sich der Einsatz spürbar vereinfacht. Dies gilt auch dann, wenn ohne ADO Express direkt auf die ADO-Objekt zugegriffen wird.

    Im folgenden Beispielprojekt wird der Inhalt einer Datei eingelesen und als binärer Inhalt in einer Image-Spalte einer SQL Server 7-Datenbanktabelle abgelegt. Anschliessend liest das Programm den gespeicherten Inhalt über eine SELECT-Abfrage neu ein und speichert diese Daten unter einem anderen Dateinamen wieder ab. Sie können somit leicht nachprüfen, ob Sie am Ende tatsächlich wieder das erhalten, was am Anfang in der Datenbank abgelegt wurde.

    Das Beispielprogramm stellt die private Methode InitDatabase zur Verfügung, damit bei Bedarf die Tabelle StreamBLOBDemo in der SQL Server 7-Datenbank angelegt werden kann. Der Spaltentyp Image ist für das Ablegen von binären Daten geeignet.
    <pre>
    procedure TForm1.InitDatabase;
    const
    SQL1 = 'DROP TABLE StreamBLOBDemo';
    SQL2 = 'CREATE TABLE StreamBLOBDemo ('+
    'ID int NOT NULL CONSTRAINT PK_StreamBLOBTest PRIMARY KEY,' +
    'FileContents image)';
    var
    swSQL : WideString;
    iRecs : Integer;
    begin
    swSQL := SQL1;
    try
    ADOConnection1.Execute(swSQL, iRecs, [eoExecuteNoRecords]);
    except
    // falls Tabelle noch nicht vorhanden
    end;
    swSQL := SQL2;
    ADOConnection1.Execute(swSQL, iRecs, [eoExecuteNoRecords]);
    end;
    </pre>
    Mit dem Importieren der Typbibliothek von ADO 2.5 stehen in der TLB.pas auch die CoClass-Einträge für das Recordset- und Stream-Objekt von ADO zur Verfügung. Das Programm kann somit diese beiden Objekt direkt anfordern. Aus Bequemlichkeit habe ich für die ADO-Connection eine TADOConnection-Instanz eingesetzt, aber falls ADO Express nicht zur Verfügung steht, kann auch TADOConnection direkt durch das Connection-Objekt von ADO ersetzt werden.

    Über eine "unsinnige"“ SELECT-Abfrage wird eine garantiert leere Datenmenge im Recordset geöffnet:
    <pre>
    SELECT ID, FileContents FROM StreamBLOBDemo WHERE 1 = 0
    </pre>
    Somit muss das Recordset-Objekt keine Daten vom SQL Server laden, so dass über den Aufruf von AddNew gleich ein neuer Datensatzpuffer angefordert wird. Über die Fields-Kollektion des Recordset-Objekts übergibt das Programm die Daten für beide Spalten des neuen Datensatzes, so dass dieser Datensatz über den Aufruf von Update gespeichert werden kann, ohne dass der SQL Server 7 einen fehlenden Primärschlüsselwert bemängelt. War das erfolgreich, liest das Programm den gerade neu angelegten Datensatz über eine zweite SELECT-Abfrage wieder ein. Nun wird in der WHERE-Einschränkung der gerade eingefügte Primärschlüsselwert verwendet, so dass die Datenbank garantiert nur einen einzigen Datensatz zurückliefert.
    <pre>
    SELECT ID, FileContents FROM StreamBLOBDemo WHERE ID = 5
    </pre>
    Wird nun eine neue Instanz des Stream-Objekts erzeugt, kann dieses über die Write-Methode die als Parameter übergebenen Daten in den eigenen Stream schreiben. Ist das erledigt, speichert der Aufruf von SaveToFile diese Streamdaten in einer Datei ab.
    <pre>
    procedure TForm1.ToolButtonBLOBClick(Sender: TObject);
    resourcestring
    RS_SQL = 'SELECT ID, FileContents FROM StreamBLOBDemo WHERE 1 = 0';
    SELECT = 'SELECT ID, FileContents FROM StreamBLOBDemo WHERE ID = ';
    var
    aADOStream : _Stream;
    aRS : _RecordSet;
    iID : Integer;
    vSQL : OleVariant;
    begin
    // Step 1: ADO-Stream-Objekt initialisieren
    aADOStream := CoStream.Create;
    aADOStream.Type_ := adTypeBinary;
    aADOStream.Open(EmptyParam, adModeUnknown,
    adOpenStreamUnspecified, '', '');
    aADOStream.LoadFromFile(FFileName);
    // Step 2: ADO-Recordset-Objekt initialisieren
    aRS := CoRecordset.Create;
    aRS.CursorLocation := adUseClient;
    vSQL := RS_SQL;
    aRS.Open(vSQL, ADOConnection1.ConnectionObject,
    adOpenStatic, adLockOptimistic, adCmdText);
    // Step 3: Neuen Datensatzpuffer anfordern
    aRS.AddNew(EmptyParam, EmptyParam);
    iID := StrToInt(EditID.Text);
    // Step 4: Werte zuweisen, BLOb aus Stream-Objekt zuordnen
    aRS.Fields.Item['ID'].Value := iID;
    aRS.Fields.Item['FileContents'].Value := aADOStream.Read(adReadAll);
    // Step 5: Datensatz speichern
    aRS.Update(EmptyParam, EmptyParam);
    aRS.Close;
    aADOStream.Close;
    aRS := nil;
    aADOStream := nil;
    // Step 6: Datensatz zur Kontrolle neu einlesen
    aRS := CoRecordset.Create;
    vSQL := SELECT + IntToStr(iID);
    aRS.Open(vSQL, ADOConnection1.ConnectionObject,
    adOpenForwardOnly, adLockReadOnly, adCmdText);
    // BLOb-Inhalt via Stream-Objekt auslesen und speichern
    aADOStream := CoStream.Create;
    aADOStream.Type_ := adTypeBinary;
    aADOStream.Open(EmptyParam, adModeUnknown,
    adOpenStreamUnspecified, '', '');
    aADOStream.Write(aRS.Fields.Item['FileContents'].Value);
    aADOStream.SaveToFile(FSaveFileName, adSaveCreateOverWrite);
    aADOStream.Close;
    aRS.Close;
    Inc(iID);
    EditID.Text := IntToStr(iID);
    end;
    </pre>
    P.S: Wenn der Zugriff über das Stream-Objekt mit dem ODBC-Treiber nicht funktioniert, liegt es <b>nicht</b> an ADO, sondern am ODBC-Treiber

    Comment


    • #3
      Hallo Herr Kosch,

      ich habe das oben aufgeführte Beispiel dazu benutzt um aus einer bestehenden DB (MS SQL 7) Bilder zu exportieren. Nun habe ich das Problem, dass immer wieder Datensätze dazwischen sind die bei dem Versuch aRS zu öffnen den Fehler "Bei der Konvertierung des varChar-Wertes 3300597 in einer Spalte vom Datentyp int" hervorrufen.

      Meine Suche nach Hinweisen auf diesen Fehler verliefen erfolglos... Denn es handelt sich bei dem Feld um den Datentyp Image und nicht um nvarchar oder int.

      Bitte helfen Sie mir….. Danke Ola

      Comment


      • #4
        Hallo,

        an welcher Stelle wird diese Fehlermeldung ausgelöst, wenn die Aufrufe im Debugger schrittweise abgearbeitet werden? Wird die Stream-Objektinstanz auch wirklich im Modus adTypeBinary betrieben

        Comment


        • #5
          Hallo,

          der Fehler tritt bei öffnen der Datenmenge auf! Ich habe aber mittlerweile eine Lösung gefunden und bedanke mich rechtherzlich für die rasche Antwort!!

          Ola

          Comment

          Working...
          X