hat jemand einen guten Tipp, wie ich einen kompletten Record, den ich in meinem
Delphi-Programm definiert habe, als ein Datenfeld in einer Datenbank (MySQL)
speichen kann? Ich denke, dass es einen Weg über ein Blob-Feld geben könnte.
Da ich lieber Query- als Tableobjekte verwende, sollte das Ganze (schreiben und
lesen) in Form von SQL-Befehlen erfolgen. Wie bringe ich nun den Inhalt des
strukturierten Feldes in einem SQL-Befehl (z. B. INSERT ...) unter, der ja aus
Strings und nicht aus binären Daten besteht?
Ich denke, das Problem ist allgemeingültig für jede Form von binären Daten.
Vielleicht hat jemand Erfahrung damit oder eine gute Idee?
Steffen.
--
__________________________________________________________
News suchen, lesen, schreiben mit http://newsgroups.web.de
>
> hat jemand einen guten Tipp, wie ich einen kompletten Record, den ich in
meinem
> Delphi-Programm definiert habe, als ein Datenfeld in einer Datenbank
(MySQL)
> speichen kann? Ich denke, dass es einen Weg über ein Blob-Feld geben
könnte.
> Da ich lieber Query- als Tableobjekte verwende, sollte das Ganze
(schreiben und
> lesen) in Form von SQL-Befehlen erfolgen. Wie bringe ich nun den Inhalt
des
> strukturierten Feldes in einem SQL-Befehl (z. B. INSERT ...) unter, der ja
aus
> Strings und nicht aus binären Daten besteht?
>
>
> Ich denke, das Problem ist allgemeingültig für jede Form von binären
Daten.
> Vielleicht hat jemand Erfahrung damit oder eine gute Idee?
>
Wenn du eine "normale Afrage" verwendest:
"SELECT * FROM MyTable"
dann kann du so Blob-Daten einfügen:
Query1.Insert;
Query1.FieldByName('Key').AsString := 'Test';
SetString(s, pmyrecord, sizeof(TMyRecord));
Query1.FieldByName('MyBLOB').AsString := s;
Query1.Post;
Achtung !!!!
Dein Record darf keine Ansi-Strings enthalten, da ein
Ansi-String im Speicher nur ein Zeiger auf die eigentlichen
Stringdaten ist.
Gruß
Andreas
> Ich denke, dass es einen Weg über ein Blob-Feld geben könnte.
Ja. Dazu wäre ein TBlobStream geeignet.
> Da ich lieber Query- als Tableobjekte verwende, sollte das Ganze
> (schreiben und lesen) in Form von SQL-Befehlen erfolgen.
Dann brauchst Du parametrisierte INSERT-Statements:
INSERT INTO Tabelle (DasBlobFeld) VALUES (:DasBlobFeld);
Zum Schreiben weist Du der Eigenschaft AsBlob des Parameters einen String
zu.
Einen String? Ja, einen String. In Delphi kann ein String beliebige Daten
aufnehmen, ein AnsiString sogar praktisch beliebig viele beliebige Daten.
Also zum Beispiel:
S:=TStringStream.Create('');
try
S.Write(DerRecord,SizeOf(DerRecord));
Query1.ParamByName('DasBlobFeld').AsBlob:=S.DataString;
finally
S.Free;
end;
> Ich denke, das Problem ist allgemeingültig für jede Form von binären
> Daten.
Ist es. Aber bist Du Dir sicher, daß Du binäre Daten schreiben willst? Eine
Alternative zu einzelnen Feldern wäre ein Memo-Feld, in das Du eine Liste
von Name=Wert-Paaren schreibst. Das ist auch außerhalb Deines Programms
verständlich, und nicht abhängig von Kleinigkeiten wie "packed", den Größen
von Datentypen, oder (zukünftig) der Endianness der Maschine.
Ciao, MM
--
Marian Aldenhövel, Hainstraße 8, 53121 Bonn
http://www.marian-aldenhoevel.de
"War does not determine who is right, only who is left"
Das klingt gut - werde ich heute gleich versuchen!
Vielen Dank!
>> Ich denke, das Problem ist allgemeingültig für jede Form von binären
>> Daten.
>
>Ist es. Aber bist Du Dir sicher, daß Du binäre Daten schreiben willst? Eine
>Alternative zu einzelnen Feldern wäre ein Memo-Feld, in das Du eine Liste
>von Name=Wert-Paaren schreibst. Das ist auch außerhalb Deines Programms
>verständlich, und nicht abhängig von Kleinigkeiten wie "packed", den Größen
>von Datentypen, oder (zukünftig) der Endianness der Maschine.
Habe ich mir auch schon überlegt. Das erfordert aber Routinen im Delphi-Programm
zum Ein- und Auslesen der (umfangreichen) Daten aus dem Record in die Textform
und umgekehrt.
>
>Ciao, MM
Das klingt gut - werde ich heute gleich versuchen!
>Marian Aldenhövel, Hainstraße 8, 53121 Bonn
>http://www.marian-aldenhoevel.de
>"War does not determine who is right, only who is left"
Das kann ich nur unterstützen!!!
Gruß Steffen
> Habe ich mir auch schon überlegt. Das erfordert aber Routinen im
> Delphi-Programm zum Ein- und Auslesen der (umfangreichen) Daten aus dem
> Record in die Textform und umgekehrt.
Ja, das tut es. Aber wer, wenn nicht Dein Programm, kann das leisten? Das
ist genau der richtige Platz dafür - niemand kennt die Daten so gut.
Vielleicht hilft noch ein weiteres Argument dabei Dich zu überzeugen:
Wenn Version 1.0 Deines Programms die erste Million Datensätze vollhat,
fällt Dir ein, daß Du Deinen Record für Version 1.0a um ein weiteres Feld
erweitern möchtest.
Dann bemerkst Du auf unangenehme Weise, daß das in der binären Form
nicht vernünftig geht.
Es kommt dann in jedem Fall etwas murksiges dabei heraus. Jede zukünftige
Version des Programms muss dann alle Recordformate aller bereits längst
verstorbenen Versionen kennen und unterstützen. Der Code muss dann "raten"
welche Version der Daten in einem gegebenen Record vorliegt und schließlich
doch feldweise konvertieren.
Mit der Textfassung gibst Du einfach für das neue Feld einen Defaultwert
vor und liest immer nur das, was da ist. Wenn Du wider Erwarten in neuen
Versionen Felder streichen solltest, kannst Du sie beim Lesen ebenso leicht
ignorieren.
Ciao, MM
--
Deine Argumente haben mich überzeugt. Ich werde die Textform wählen - ist
wirklich flexibler.
Aber nur interessehalber für Daten, die wirklich binär sind, wie pdf-Dateien,
Bilder, formatierte Text-Dokumente u.a. :
Nachdem ich die Daten wie von Dir vorgeschlagen speichern kann (habe es probiert -
und klappt), ist es mir leider nicht gelungen sie aus dem Datenfeld wieder
auszulesen. Ich stolpere immer wieder darüber, dass mir Delphi sagt, die
Datentypen seien inkompatibel. Was ja auch stimmt, denn über ein TStringStream
bekomme ich eben einen String zurück.
Versuche mit TBlobStream sind fehlgeschlagen. Mir fehlt da wohl noch ein
grundlegendes Aha-Erlebnis im Umgang mit Streams.
Ansonsten schon mal vielen Dank für die guten Tipps!
Gruß Steffen.
>> Habe ich mir auch schon überlegt. Das erfordert aber Routinen im
>> Delphi-Programm zum Ein- und Auslesen der (umfangreichen) Daten aus dem
>> Record in die Textform und umgekehrt.
>
>Ja, das tut es. Aber wer, wenn nicht Dein Programm, kann das leisten? Das
>ist genau der richtige Platz dafür - niemand kennt die Daten so gut.
>
>Vielleicht hilft noch ein weiteres Argument dabei Dich zu überzeugen:
>
>Wenn Version 1.0 Deines Programms die erste Million Datensätze vollhat,
>fällt Dir ein, daß Du Deinen Record für Version 1.0a um ein weiteres Feld
>erweitern möchtest.
>
>Dann bemerkst Du auf unangenehme Weise, daß das in der binären Form
>nicht vernünftig geht.
>
>Es kommt dann in jedem Fall etwas murksiges dabei heraus. Jede zukünftige
>Version des Programms muss dann alle Recordformate aller bereits längst
>verstorbenen Versionen kennen und unterstützen. Der Code muss dann "raten"
>welche Version der Daten in einem gegebenen Record vorliegt und schließlich
>doch feldweise konvertieren.
>
>Mit der Textfassung gibst Du einfach für das neue Feld einen Defaultwert
>vor und liest immer nur das, was da ist. Wenn Du wider Erwarten in neuen
>Versionen Felder streichen solltest, kannst Du sie beim Lesen ebenso leicht
>ignorieren.
>
> ist es mir leider nicht gelungen sie aus dem Datenfeld wieder
> auszulesen.
Das nennt man ein WOB, ein Write Only BLOB, als Datensenke ausgesprochen
praktisch...
> Ich stolpere immer wieder darüber, dass mir Delphi sagt, die
> Datentypen seien inkompatibel. Was ja auch stimmt, denn über ein
> TStringStream bekomme ich eben einen String zurück.
Dieser String enthält (hoffentlich) Deine Daten Bit für Bit so wie Du sie
mit Write geschrieben hast. Du kannst sie mit Read genauso wieder lesen:
S:=TStringStream.Create(FieldByName('Blob').AsBlob);
try
S.Seek(0,soFromBeginning);
S.Read(DeinRecord,SizeOf(DeinRecord));
finally
S.Free;
end;
Ob das seek nötig ist, weiß ich nicht, lies nach, wohin Create(EinString)
den TStringStream positioniert - am Anfang oder am Ende.
Du kannst auch gröber vorgehen:
Move(DeinRecord,FieldByName('Blob').AsBlob[1],SizeOf(DeinRecord));
Das ist aber noch ein klein bisschen gefährlicher als die Methode mit dem
Stream.
> Versuche mit TBlobStream sind fehlgeschlagen.
var B:TStream;
B:=Query1.CreateBlobStream(FieldByName('Blob'),bmRead);
try
B.Read(DeinRecord,SizeOf(DeinRecord));
finally
B.Free;
end;
Einziger Fallstrick ist hier die Tatsache, daß CreateBlobStream formal
einen TStream zurückgibt und keinen TBlobStream.