Delphi FDQuery 转 Json

问题描述 投票:0回答:6

我正在尝试将 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;
json delphi delphi-xe delphi-10.1-berlin firedac
6个回答
4
投票

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

  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 放在 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组件拖入datamodule
  2. 方法.Data仅适用于FiredacDatasets(带有前缀FD的数据集)。 要为旧数据集中的 memTable 分配数据,请使用方法 .Copydata 代替。
  3. 抱歉,我将
    .Data
    更改为
    .CloneCursor
    ,以便与两个数据集共享相同的内存空间。

3
投票

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


0
投票

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


0
投票

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

优点是布尔值会转换为 TJSONBool 类型而不是字符串。我建议看看样品。

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


0
投票

可能不是最好的解决方案,您可以将其修改为您想要的 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;

0
投票

我喜欢这种简单性,借助 JsonDataObjects 的强大功能,我们可能会得到 JsonObject 的结果。

使用..JsonDataObjects,

function GetDataSetAsJSON(DataSet: TDataSet): JsonDataObjects.TJSONObject;
var
  F: TField;
  JDO : JsonDataObjects.TJSONObject;
begin
  Result := TJsonObject.Create;
  DataSet.Active := True;
  DataSet.First;
  while not DataSet.EOF do
  begin
    // automatic object creation, 'ResultData' is the owner of JDO
    JDO := Result.A['ResultData'].AddObject();
    for F in DataSet.Fields do
      JDO.S[F.FieldName] := VarToStr(F.Value);
    DataSet.Next;
  end;
  DataSet.Active := False;
end;
© www.soinside.com 2019 - 2024. All rights reserved.