【问题标题】:Delphi FDQuery to JsonDelphi FDQuery 到 Json
【发布时间】:2023-03-23 04:49:01
【问题描述】:

我正在尝试将我的 Sqlite 查询结果转换为 Json, 使用与通过 php 远程绑定到 Sql Server 相同的过程。

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

有人这样做吗?

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;

【问题讨论】:

  • 您使用的是哪个特定 Delphi 版本? Delphi XE 不附带 FireDAC,因此如果您替换 q 上的 delphi-xe 标签会很有帮助。
  • 你看过docwiki.embarcadero.com/RADStudio/XE8/e/…吗?例如。部分函数 TServerMethods1.GetDepartmentNames
  • 我正在使用 Embarcadero RAD Studio 10.1 Berlin。

标签: json delphi delphi-xe delphi-10.1-berlin firedac


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    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.SaveToStreamFDMemTable.SaveToFile 也是如此; 将 TFDMemTable 放在 Datamodule(或表单)上。
            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 以便与两个数据集共享相同的内存空间。

    【讨论】:

    • 我认为解决方案 2 非常好,因为您可以根据需要控制仅保存 Delta,然后为每条记录加载原始 updateStatus。
    【解决方案3】:

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

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

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

    【讨论】:

      【解决方案4】:

      我刚刚修改了下面的第一个答案,以将不同类型的字段转换为适当的 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

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

      【讨论】:

      • 是的,你的答案是最正确的。感谢您关注不同的类型。
      【解决方案5】:

      可能不是最佳解决方案,您可以将其修改为您希望 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;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-04
        • 1970-01-01
        • 1970-01-01
        • 2017-10-18
        • 2015-11-26
        • 1970-01-01
        相关资源
        最近更新 更多