利用QJson转换FireDAC数据JSON格式

首先我们来看FireDAC的数据对象,看看它的内部保存的方式。

FireDAC数据保存,大致流程如下:

“TFDDataSet.InternalSaveToStorage”

-》“TFDDatSManager.InternalSaveToStorage”

-》“TFDDatSTable.InternalSaveToStorage”

– 》“TFDDatSColumnList.InternalSaveToStorage”

– 》“TFDDatSTableRowList.InternalSaveToStorage”

根据传入不同的Storage来获取不同的格式的Storage,通过Storage的Write和Read相关方法,来保存数据所有的数据和参数。

那我们用QJson,也是可以借鉴上面的方式来保存数据。

 

我的方法如下:

 

procedure SaveToJSON(Node: TQJson);

  procedure WriteValue(ANode: TQJson; const APropName: String; APropIndex: Word;
    ADataType: TFDDataType; ABuff: Pointer; ALen: LongWord); overload;
  const
    CDateTimeISO8601Format: String = '%.4d%.2d%.2dT%.2d%.2d%.2d';
    CTimeFormat: String = '%.2d%.2d%.2d';
    CDateFormat: String = '%.4d%.2d%.2d';
  var
    sVal: String;
    sSign: String;
    iLen: Integer;
    y, mo, d, h, mi, se, ms: Word;
    dt: TDateTime;
    pTS: PSQLTimeStamp;
    pInt: PFDSQLTimeInterval;
    rTS: TSQLTimeStamp;
    pDest: PChar;
    aFixed: array [0 .. C_FD_MaxFixedSize] of Char;
  begin
    if ABuff = nil then
      Exit;
    pDest := @aFixed[0];
    iLen := SizeOf(aFixed) div SizeOf(Char);
    case ADataType of
      dtObject,
        dtRowSetRef,
        dtCursorRef,
        dtRowRef,
        dtArrayRef,
        dtParentRowRef:
        ;
      dtWideMemo,
        dtWideHMemo,
        dtXML,
        dtWideString:

        ANode.Add(APropName, PWideChar(ABuff), jdtString);
      dtMemo,
        dtHMemo,
        dtAnsiString:
        begin
          pDest := nil;
          iLen := FQuery.Encoder.Decode(ABuff, ALen, Pointer(pDest), ecUTF16, ecANSI);
          ANode.Add(APropName, pDest, jdtString);
        end;
      dtByteString,
        dtBlob,
        dtHBlob,
        dtHBFile:
        ANode.Add(APropName, FDBin2Hex(ABuff, ALen), jdtString);
      dtBoolean:
        ANode.Add(APropName, PWord(ABuff)^ <> 0);
      dtSByte:
        begin
          FDInt2Str(ABuff, SizeOf(ShortInt), pDest, iLen, False, 0);
          ANode.Add(APropName, pDest, jdtInteger);
        end;
      dtInt16:
        begin
          FDInt2Str(ABuff, SizeOf(SmallInt), pDest, iLen, False, 0);
          ANode.Add(APropName, pDest, jdtInteger);
        end;
      dtInt32:
        begin
          FDInt2Str(ABuff, SizeOf(Integer), pDest, iLen, False, 0);
          ANode.Add(APropName, pDest, jdtInteger);
        end;
      dtInt64:
        begin
          FDInt2Str(ABuff, SizeOf(Int64), pDest, iLen, False, 0);
          ANode.Add(APropName, pDest, jdtInteger);
        end;
      dtByte:
        begin
          FDInt2Str(ABuff, SizeOf(Byte), pDest, iLen, True, 0);
          ANode.Add(APropName, pDest, jdtInteger);
        end;
      dtUInt16:
        begin
          FDInt2Str(ABuff, SizeOf(Word), pDest, iLen, True, 0);
          ANode.Add(APropName, pDest, jdtInteger);
        end;
      dtUInt32:
        begin
          FDInt2Str(ABuff, SizeOf(LongWord), pDest, iLen, True, 0);
          ANode.Add(APropName, pDest, jdtInteger);
        end;
      dtUInt64:
        begin
          FDInt2Str(ABuff, SizeOf(UInt64), pDest, iLen, True, 0);
          ANode.Add(APropName, pDest, jdtInteger);
        end;
      dtSingle:
        ANode.Add(APropName, FDFloat2Str(PSingle(ABuff)^, '.'), jdtFloat);
      dtDouble:
        ANode.Add(APropName, FDFloat2Str(PDouble(ABuff)^, '.'), jdtFloat);
      dtExtended:
        ANode.Add(APropName, FDFloat2Str(PExtended(ABuff)^, '.'), jdtFloat);
      dtCurrency:
        ANode.Add(APropName, FDFloat2Str(PCurrency(ABuff)^, '.'), jdtFloat);
      dtBCD,
        dtFmtBCD:
        begin
          FDBCD2Str(pDest, iLen, PBcd(ABuff)^, '.');
          ANode.Add(APropName, pDest, jdtFloat);
        end;
      dtDateTime:
        begin
          dt := TimeStampToDateTime(MSecsToTimeStamp(PDateTimeRec(ABuff)^.DateTime));
          DecodeDate(dt, y, mo, d);
          DecodeTime(dt, h, mi, se, ms);
          iLen := WideFormatBuf(pDest^, iLen, Pointer(CDateTimeISO8601Format)^,
            Length(CDateTimeISO8601Format), [y, mo, d, h, mi, se], FormatSettings);
          ANode.Add(APropName, pDest, jdtDateTime);
        end;
      dtDateTimeStamp:
        begin
          pTS := PSQLTimeStamp(ABuff);
          iLen := WideFormatBuf(pDest^, iLen, Pointer(CDateTimeISO8601Format)^,
            Length(CDateTimeISO8601Format), [pTS^.Year, pTS^.Month, pTS^.Day, pTS^.Hour,
            pTS^.Minute, pTS^.Second], FormatSettings);
          ANode.Add(APropName, pDest, jdtString);
        end;
      dtTimeIntervalFull,
        dtTimeIntervalYM,
        dtTimeIntervalDS:
        begin
          pInt := PFDSQLTimeInterval(ABuff);
          if pInt^.Sign < 0 then
            sSign := '-'
          else
            sSign := '';
          case pInt^.Kind of
            itYear:
              sVal := Format('%sP%uY', [sSign, pInt^.Years]);
            itMonth:
              sVal := Format('%sP%uM', [sSign, pInt^.Months]);
            itDay:
              sVal := Format('%sP%uD', [sSign, pInt^.Days]);
            itHour:
              sVal := Format('%sT%uH', [sSign, pInt^.Hours]);
            itMinute:
              sVal := Format('%sT%uM', [sSign, pInt^.Minutes]);
            itSecond:
              sVal := Format('%sT%uS%uF', [sSign, pInt^.Seconds, pInt^.Fractions]);
            itYear2Month:
              sVal := Format('%sP%uY%uM', [sSign, pInt^.Years, pInt^.Months]);
            itDay2Hour:
              sVal := Format('%sP%uDT%uH', [sSign, pInt^.Days, pInt^.Hours]);
            itDay2Minute:
              sVal := Format('%sP%uDT%uH%uM', [sSign, pInt^.Days, pInt^.Hours, pInt^.Minutes]);
            itDay2Second:
              sVal := Format('%sP%uDT%uH%uM%uS%uF', [sSign, pInt^.Days, pInt^.Hours, pInt^.Minutes, pInt^.Seconds, pInt^.Fractions]);
            itHour2Minute:
              sVal := Format('%sT%uH%uM', [sSign, pInt^.Hours, pInt^.Minutes]);
            itHour2Second:
              sVal := Format('%sT%uH%uM%uS%uF', [sSign, pInt^.Hours, pInt^.Minutes, pInt^.Seconds, pInt^.Fractions]);
            itMinute2Second:
              sVal := Format('%sT%uM%uS%uF', [sSign, pInt^.Minutes, pInt^.Seconds, pInt^.Fractions]);
          end;
          ANode.Add(APropName, sVal, jdtString);
        end;
      dtTime:
        begin
          rTS := FDTime2SQLTimeStamp(PLongint(ABuff)^);
          iLen := WideFormatBuf(pDest^, iLen, Pointer(CTimeFormat)^,
            Length(CTimeFormat), [rTS.Hour, rTS.Minute, rTS.Second], FormatSettings);
          ANode.Add(APropName, pDest, jdtDateTime);
        end;
      dtDate:
        begin
          rTS := FDDate2SQLTimeStamp(PLongint(ABuff)^);
          iLen := WideFormatBuf(pDest^, iLen, Pointer(CDateFormat)^,
            Length(CDateFormat), [rTS.Year, rTS.Month, rTS.Day], FormatSettings);
          ANode.Add(APropName, pDest, jdtDateTime);
        end;
      dtGUID:
        ANode.Add(APropName, GUIDToString(PGUID(ABuff)^), jdtString);
    end;
  end;

var

  lNode, lRowsNode, lRowNode: TQJson;

  i, j: Integer;
  oRows: TFDDatSTableRowList;
  oRow: TFDDatSRow;
  oCols: TFDDatSColumnList;
  oCol: TFDDatSColumn;

  pBuff: Pointer;
  iLen: LongWord;
begin
  if FQuery <> nil then
  begin
    oRows := FQuery.Table.Rows;
    oCols := FQuery.Table.Columns;

    lNode := Node.Add('data', jdtObject);
    lRowsNode := lNode.AddArray('rows');

    for i := 0 to oRows.Count - 1 do
    begin
      oRow := oRows.ItemsI[i];
      lRowNode := lRowsNode.Add();
      for j := 0 to oCols.Count - 1 do
      begin
        pBuff := nil;
        iLen := 0;
        oCol := oCols.ItemsI[j];

        oRow.GetData(j, rvDefault, pBuff, 0, iLen, False);
        WriteValue(lRowNode, oCol.Name, j, oCol.DataType, pBuff, iLen);
      end;
    end;
  end;
end;

 

这样的保存方式,滚动的效率上比。你们自已测试一下就知道了,我不说了。

 

我做过对比,这样保存效率的差距是在QJson的SaveToStream这一步。期待swish的QDAC3.0。

 

分享到: