Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi FDQuery to Json

I'm trying to convert the result of my Sqlite query into a Json, to use the same procedures I use with remote binding to Sql Server by php.

The code works, but do you think it's a better solution?

Anyone there do that?

function TLogin.RetornaRegistros(query:String): String;
var
  FDQuery : TFDQuery;
  field_name,nomeDaColuna,valorDaColuna : String;
  I: Integer;
begin
    FDQuery := TFDQuery.Create(nil);
    try
      FDQuery.Connection := FDConnection1;
      FDQuery.SQL.Text := query;
      FDQuery.Active := True;
      FDQuery.First;

      result := '[';
      while (not FDQuery.EOF) do
      begin

        result := result+'{';
        for I := 0 to FDQuery.FieldDefs.Count-1 do
        begin
          nomeDaColuna  := FDQuery.FieldDefs[I].Name;
          valorDaColuna := FDQuery.FieldByName(nomeDaColuna).AsString;
          result := result+'"'+nomeDaColuna+'":"'+valorDaColuna+'",';
        end;
        Delete(result, Length(Result), 1);
        result := result+'},';

        FDQuery.Next;
      end;
      FDQuery.Refresh;

      Delete(result, Length(Result), 1);
      result := result+']';

    finally
      FDQuery.Free;
    end;
end;
like image 260
João Rodrigues Avatar asked Aug 10 '26 05:08

João Rodrigues


1 Answers

That is not a good approach. I really suggest consider at least three options:

  1. Use the power of System.JSON unit.
Uses {...} System.JSON;
        
    Var    
    FDQuery : TFDQuery;
    field_name,Columnname,ColumnValue : String;
    I: Integer;

    LJSONObject:TJsonObject;
    begin
        FDQuery := TFDQuery.Create(nil);
        try
          FDQuery.Connection := FDConnection1;
          FDQuery.SQL.Text := query;
          FDQuery.Active := True;
          FdQuery.BeginBatch;//Don't update external references until EndBatch;
          FDQuery.First;
          LJSONObject:= TJSONObject.Create;
          while (not FDQuery.EOF) do
          begin
                for I := 0 to FDQuery.FieldDefs.Count-1 do
                begin
                  ColumnName  := FDQuery.FieldDefs[I].Name;
                  ColumnValue := FDQuery.FieldByName(ColumnName).AsString;
                  LJSONObject.AddPair(TJSONPair.Create(TJSONString.Create( ColumnName),TJSONString.Create(ColumnValue)));
                FDQuery.Next;
              end;
              //FDQuery.Refresh; that's wrong
             FdQuery.EndBatch;
            finally 
              FDQuery.Free;
              Showmessage(LJSonObject.ToString);
            end;
        end;
https://www.youtube.com/watch?v=MLoeLpII9IE&t=715s
  1. Second approach, use FDMemTable.SaveToStream; The same works for FDMemTable.SaveToFile; Put a TFDMemTable on Datamodule (Or form, as well).
        fMStream:TMemoryStream;
        Begin       
        FDQuery := TFDQuery.Create(nil);
           try
              FDQuery.Connection := FDConnection1;
              FDQuery.SQL.Text := query;
              FDQuery.Active := True;
              //fdMemTable1.Data:=fdQuery.Data; {note *2}
              fdMemTable1.CloneCursor(FdQuery,true,true);{note *3}
              fMStream:=TMemoryStream.Create;
              FdMemTable1.SaveToStream(fMStream,sfJson);
           finally
               FDQuery.Free;
               FdMemTable.Close;
           end;

Now you can Read the JSON content

For example, following answer Converting TMemoryStream to 'String' in Delphi 2009

function MemoryStreamToString(M: TMemoryStream): string;
begin
      SetString(Result, PChar(M.Memory), M.Size div SizeOf(Char));
end;

and you have the json as String

  1. The BatchMove suggeted by @VictoriaMarotoSilva

You can use BatchMove components, which provides an interface to move data between datasets, but it works better for backup and importation when you want to save data in drive, XML or json format. I didn't find examples yet, using data moving in memory; if somebody else has an example, please comment.

Notes

  1. Using FdMemTable, don't forget drag TFDStanStorageJSONLink component for datamodule
  2. method .Data just works for FiredacDatasets (Datasets with prefix FD). To assign data for memTable in old Datasets use method .Copydata instead.
  3. Sorry guys, I change .Data to .CloneCursor to share the same Memory Space with both datasets.

Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!