restdelphiblobfiredacfiremonkey-fm3

How to store blob to database thru Datasnap REST server?


Preample:

We use a Firemonkey application then interact with a DataSnap REST Server. This server use a SQLite database. On the client side, we use FireDac Memtable to manage data. Usually for updating data, we edit the FDMemTable, then we use a function called ApplyUpdate which (in few words) create a TFDJSONDeltas, then pass it to server for applying updates. This work well for all "standard" data type.

Now we have to store a blob in the database which is the logo of the enterprise.

Some investigations:

We've found some exemple that use PARAMS and EXECUTE function of FDQuery but we do not have a FDQuery on the client side. Many of the example are for FDQuery, we do not see a sample for FDMemTable. FDMemtable do not have ExecSQL function.

We also see many algo with TBlobStream, (but unless we miss the right unit declaration), this object seem not be implemented on the Firemonkey side.

Question:

There is a way to perform this task using the FDMemTable or is it better to first upload the image to server and then let the server perform the task to add the image to blob field ?


Solution

  • I can send blob fields to DataSnap REST Server with something like this:

    client side:

    var
       mes: TMemoryStream;
       FDMemUp: TFDMemTable;
       LDeltaList: TFDJSONDeltas;
      begin
       mes:= TMemoryStream.Create;
    
       FDMemUp:= TFDMemTable.Create(nil);
       FDMemUp.CachedUpdates:= true;
       FDMemUp.FieldDefs.Add('IMAGE',ftBlob);
       FDMemUp.FieldDefs.Add('ID',ftInteger);
       FDMemUp.CreateDataSet;
    
       //append one record with blob field filled from stream
       FDMemUp.Append;
       (FDMemUp.FieldByName('ID') as TIntegerField).AsInteger:= 106;
       (FDMemUp.FieldByName('IMAGE') as TBlobField).LoadFromStream(mes);
       FDMemUp.Post;
    
       //send dataset to server 
       try
        try
          LDeltaList:= TFDJSONDeltas.Create;
          TFDJSONDeltasWriter.ListAdd(LDeltaList, 'INFOLOGO', FDMemUp);
          Result:= DM.ServerCoreClient.SendData(LDeltaList);
        except
          Result:= nil;
        end;
       finally
        FreeAndNil(FDMemUp);
        FreeAndNil(mes);
       end;
    

    Then process data at server side:

    function TDMCore.SendData(const ADeltaList: TFDJSONDeltas): boolean;
    var
     LApply: IFDJSONDeltasApplyUpdates;
     mes: TMemoryStream;
    begin
     LApply:= TFDJSONDeltasApplyUpdates.Create(ADeltaList);
     if (LApply.Values[0].RecordCount > 0) then
      begin
       mes:= TMemoryStream.Create;
       LApply.Values[0].First;
       while not LApply.Values[0].Eof do
        begin
         mes.Clear;
         //read stream data from blob field
         (LApply.Values[0].Fields[1] as TBlobField).SaveToStream(mes);
         mes.Position:= 0;
         //Use stream to insert in a database or create a image or whatever the stream represent
         LApply.Values[0].Next;
        end;
       result:= true;
      end else result:= false;
     end;