![]() |
Datenbank: Firebird • Version: 2.5 • Zugriff über: DataSnap
DataSnap DataSet übertragen mit Blobfelder macht Probleme
Liste der Anhänge anzeigen (Anzahl: 3)
Hallo Zusammen,
das Problem vorab: Wenn ein Dataset vom DataSnapServer zum einem DataSnapClient transportiert wird welches mehrere Records beinhaltet die auch ein binary Blob beinhalten, können die Blobinhalte verloren gehen! Der Blob Inhalt wird massiv vergrössert. Um das zu demonstrieren habe ich auch eine Testanwendung erzeugt mit einem DataSnapServer und ein DataSnapClient. Die Datenbank ist eine Firebird DB mit einer Tabelle. Die Tabelle beinhaltet 15 Records. Die ersten fünf Bilder sind gleich mit einer Größe von 2kb(2338). Die nächsten fünf Bilder ebenfalls gleich mit 22kb(21959) und die nächsten fünf Bilder ebenfalls gleich mit einer Größe von 263kb(263368) (Screen shot "AllImages") Rufe ich das komplette DataSet mit alle 15 Bilder ab und speichere sie auf der Platte, ist zu sehen: -die ersten fünf 2kb Bilder sind gleich. -die nächsten fünf Bilder mit je 22kb wird jedes zweite und den Faktor 100 vergrößert -die letzten fünf Bilder mit je 263kb sind wieder gleich. (Screen shot "ImagesOneIaATime") Rufe ich die Bilder so ab dass das DataSet immer nur ein Record liefert, werden alle 15 Bilder mit der richtigen Größe abgerufen. Hat jemand eine Idee warum das so ist? Dürfen in DataSets die mehr wie ein Record haben keine Blob Felder enthalten, ist da was bekannt? Kann das auch bei String Blobs passieren? //Server Methoden um das DataSet zu liefern
Delphi-Quellcode:
function TdmDAL.GetIMAGES: TDataSet;
var oQuery: TFDQuery; begin result := nil; oQuery := nil; oQuery := TFDQuery.Create(nil); try TThread.Synchronize(nil, procedure begin oQuery.Connection := FDConnection1; oQuery.FetchOptions.AutoFetchAll := afAll; oQuery.FetchOptions.RecordCountMode := cmTotal; oQuery.SQL.add('/*Get all images*/'); oQuery.SQL.add('SELECT *'); oQuery.SQL.add('FROM IMAGES'); oQuery.Open; end); result := oQuery; finally // oQuery.Free; end; end; function TdmDAL.GetIMAGE(ImageID:integer): TDataSet; var oQuery: TFDQuery; begin result := nil; oQuery := nil; oQuery := TFDQuery.Create(nil); try TThread.Synchronize(nil, procedure begin oQuery.Connection := FDConnection1; oQuery.FetchOptions.AutoFetchAll := afAll; oQuery.FetchOptions.RecordCountMode := cmTotal; oQuery.SQL.add('/*Get all images*/'); oQuery.SQL.add('SELECT *'); oQuery.SQL.add('FROM IMAGES'); oQuery.SQL.add('WHERE IMAGEID = :IMAGEID'); oQuery.Params[0].Value := ImageID; oQuery.Open; end); result := oQuery; finally // oQuery.Free; end; end; //Client Methoden um die Images vom Server abzurufen.
Delphi-Quellcode:
Gruß KostasFunction SaveBlobIntoFile(aField: TField; aFile: String): Boolean; Var S : TStream; FileS : TFileStream; begin Result := False; If Not aField.IsBlob Then Exit; // If aField.IsNull Then EXIT; S := aField.DataSet.CreateBlobStream(aField, bmRead); FileS := TFileStream.Create(aFile, fmCreate); Try Try FileS.CopyFrom(S, S.Size); Result := FileExists(aFile); Except on e:exception Do Begin Result := False; End; End; Finally S.Free; FileS.Free; End; end; procedure TfrClientMain.Button1Click(Sender: TObject); var LDataSet: TDataSet; ImagaPath:String; begin if not dmComm.InitConnection then exit; try LDataSet := dmComm.ClientContainer.FProxyInst.GetIMAGES; LDataSet.Open; LDataSet.first; ImagaPath := ExtractFilePath(Application.ExeName) + 'Images\'; ForceDirectories(ImagaPath); while not LDataSet.Eof do begin SaveBlobIntoFile(LDataSet.FieldByName('IMAGE'), ImagaPath + LDataSet.FieldByName('IMAGEID').AsString+'.png'); LDataSet.Next; end; ShellExecute(Handle, nil, PChar(ImagaPath), nil, nil, SW_SHOW); finally dmComm.CloseConnection; end; end; procedure TfrClientMain.Button2Click(Sender: TObject); begin if not dmComm.InitConnection then exit; try Edit1.text := dmComm.ClientContainer.FProxyInst.ReverseString(Edit1.text); finally dmComm.CloseConnection; end; end; procedure TfrClientMain.Button3Click(Sender: TObject); var LDataSet: TDataSet; ImagaPath:String; i:integer; begin if not dmComm.InitConnection then exit; try ImagaPath := ExtractFilePath(Application.ExeName) + 'Images\'; ForceDirectories(ImagaPath); for i := 1 to 15 do begin if Assigned(LDataSet) and LDataSet.Active then LDataSet.close; LDataSet := dmComm.ClientContainer.FProxyInst.GetIMAGE(i); LDataSet.Open; LDataSet.first; SaveBlobIntoFile(LDataSet.FieldByName('IMAGE'), ImagaPath + LDataSet.FieldByName('IMAGEID').AsString+'.png'); end; ShellExecute(Handle, nil, PChar(ImagaPath), nil, nil, SW_SHOW); finally dmComm.CloseConnection; end; end; |
AW: DataSnap DataSet übertragen mit Blobfelder macht Probleme
Ohne das jetzt im einzelnen zu analysieren, nur zwei Dinge, die mir direkt auffallen:
Ich verwende mittlerweile eigentlich nur noch das Verfahren mit
Delphi-Quellcode:
, wie es in
TFDJSONDataSets
![]() Die Queries setze ich auch im Designer auf das Datenmodul. Dann sind sie sicher über den gesamten Client-Call vorhanden und werden mit dem Datenmodul freigegeben. |
AW: DataSnap DataSet übertragen mit Blobfelder macht Probleme
Zitat:
Zu Punkt 2: Wenn ich die Query frei gebe, knallt es. Irgend wo habe ich es gelesen dass die Freigabe DataSnap übernimmt. Ich habe auch Langzeittest durchgeführt und feststellen können dass das DataSet wirklich sauber freigegeben wird. Zumindest wurde nicht mehr Speicher beansprucht. Ich werde die Tage das Beispiel umbauen nach TFDJSONDataSets. Mal sehen wie sich das verhält. Herzlichen Dank Uwe. Gruß Kostas |
AW: DataSnap DataSet übertragen mit Blobfelder macht Probleme
Zitat:
|
AW: DataSnap DataSet übertragen mit Blobfelder macht Probleme
Hallo Uwe,
ich habe umgestellt auf TFDJSONDataSets und es funktioniert deutlich besser. Zumindest haben die Bilder immer die gleiche Größe, egal ob ich Sie einzeln abrufe oder alle auf einmal. Jetzt habe ich mich auch erinnert warum ich TDataSet verwendet habe und nicht TFDJSONDataSets. Der Hintergrund, die Clients führen ein Select über TDataSet durch. Das TDataSet wird zum DataSnapServer übertragen. Der Server empfängt das DataSet und exportiert daraus ein JSON String. Dieses JSON String wird danach in einer FirebirdDB in ein Blob-Feld abgelegt. Mehrere Clients können diese Pakete abrufen. Die Pakete bleiben bis zu zwei Jahre in der DB bis sie entsorgt werden. Wir hatten schon mal darüber gesprochen und festgestellt, dass sich das JSON Format von TFDJSONDataSets in der Zukunft ändern könnte. Wenn sich das interne Format ändern würde, könnte ich die Daten aus meinen Blobs nicht importieren. Deshalb das DataSet. Ist natürlich auch keine Garantie dass sich das JSON Format nicht ändert. Gruß Kostas |
AW: DataSnap DataSet übertragen mit Blobfelder macht Probleme
FireDAC verwendet seit einiger Zeit eine Versionierung des Stream-Formats. Damit lassen sich auch in neueren FireDACs die alten Streams noch lesen. Umgekehrt gilt das logischerweise nicht.
|
AW: DataSnap DataSet übertragen mit Blobfelder macht Probleme
Zitat:
Besten Dank Uwe. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:08 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz