Delphi FDQuery 到 Json

Delphi FDQuery to Json

我正在尝试将 Sqlite 查询的结果转换为 Json, 使用与 php.

远程绑定到 Sql 服务器相同的程序

代码有效,但您认为这是更好的解决方案吗?

有人这样做吗?

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;

考虑使用 TFDBatchMove 组件。它用于在具有附加映射支持的两个数据库之间直接传输数据。作为源和目标可以是文本、数据集或对任何 FireDAC 支持的数据库引擎的 SQL 查询。

这不是一个好方法。我真的建议至少考虑三个选项:

  1. 使用System.JSON单位的力量。
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. 第二种方法,使用FDMemTable.SaveToStream同样适用于 FDMemTable.SaveToFile 将 TFDMemTable 放在数据模块(或表单)上。
        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;

现在您可以阅读JSON内容

例如,下面的回答Converting TMemoryStream to 'String' in Delphi 2009

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

并且您将 json 作为字符串

  1. @VictoriaMarotoSilva 建议的 BatchMove

您可以使用 BatchMove 组件,它提供了一个在数据集之间移动数据的接口,但是当您想将数据保存在驱动器中时,它更适合备份和导入,XML 或 json 格式。我还没有找到例子,使用内存中移动的数据;如果其他人有示例,请发表评论。

备注

  1. 使用FdMemTable,不要忘记将TFDStanStorageJSONLink 组件拖到数据模块
  2. method .Data 仅适用于 FiredacDatasets(前缀为 FD 的数据集)。 要在旧数据集中为 memTable 分配数据,请改用方法 .Copydata。
  3. 抱歉,我将 .Data 更改为 .CloneCursor 以与两个数据集共享相同的内存 Space。

Delphi MVC Framework 包含一个强大的映射器,可以将 json 映射到对象以及将数据集映射到对象。 Mapper 是一个子项目。它是独立的代码,也可以用于其他类型的项目。它是开源的!

优点是例如布尔值被转换为 TJSONBool 类型而不是字符串。我建议看一下示例。

https://github.com/danieleteti/delphimvcframework/tree/master/samples/objectsmapperssamples

我刚刚修改了下面的第一个答案,将不同类型的字段转换为适当的 json 格式的数字、日期和布尔值。 我评论我没有测试的类型。 看

使用{...} 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;

              Case FDQuery.FieldDefs[I].Datatype of
                  ftBoolean: 
                    IF FDQuery.FieldDefs[I].Value=True then   LJSONObject.AddPair(TJSONPair.Create(TJSONString.Create( ColumnName),TJSONTrue.Create)) else 
                      LJSONObject.AddPair(TJSONPair.Create(TJSONString.Create( ColumnName),TJSONFalse.Create)); 
                  ftInteger,ftFloat{,ftSmallint,ftWord,ftCurrency} :
                    LJSONObject.AddPair(TJSONPair.Create(TJSONString.Create( ColumnName),TJSONNumber.Create(FDQuery.FieldDefs[I].value)));   
                  ftDate,ftDatetime,ftTime:
                   LJSONObject.AddPair(TJSONPair.Create(TJSONString.Create( ColumnName),TJSONString.Create(FDQuery.FieldDefs[I].AsString)));
//or TJSONString.Create(formatDateTime('dd/mm/yyyy',FDQuery.FieldDefs[I].Value));
                  else LJSONObject.AddPair(TJSONPair.Create(TJSONString.Create( ColumnName),TJSONString.Create(FDQuery.FieldDefs[I].AsString)));
              End;

            FDQuery.Next;
          end;
         FdQuery.EndBatch;
        finally 
          FDQuery.Free;
          Showmessage(LJSonObject.ToString);
        end;
    end;

更多关于 dataset.DataType http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/DB_TFieldType.html

关于 JSONType 的更多信息https://community.embarcadero.com/blogs/entry/json-types-for-server-methods-in-datasnap-2010-4

可能不是最好的解决方案,您可以将其修改为您希望如何格式化 JSON...这是一个快速示例解决方案:

function GetDataSetAsJSON(DataSet: TDataSet): TJSONObject;
var
  f: TField;
  o: TJSOnObject;
  a: TJSONArray;
begin
  a := TJSONArray.Create;
  DataSet.Active := True;
  DataSet.First;
  while not DataSet.EOF do begin
    o := TJSOnObject.Create;
    for f in DataSet.Fields do
      o.AddPair(f.FieldName, VarToStr(f.Value));
    a.AddElement(o);
    DataSet.Next;
  end;
  DataSet.Active := False;
  Result := TJSONObject.Create;
  Result.AddPair(DataSet.Name, a);
end;