吾八哥博客

您现在的位置是:首页 > 码农手记 > Delphi > 正文

Delphi

实现通用的ISQLDBRows转换为Object数组的方法

吾八哥2017-12-03Delphi3651

最近在使用mORMot写一个服务端,利用TODBCConnectionProperties操作MYSQL数据库,遇到查询查询数据库后需要将返回的ISQLDBRows转换为对象数组。其实ISQLDBRows自带转为为JSON字符串的方法FetchAllAsJSON,但我这里是要转换为对象数组,例如查询用户表后返回的是用户数据列表,查询文章表后返回的是文章数据列表,甚至后面还可能有评论列表,如果都一个个的去写解析方法,实在太繁琐了,就想实现一个通用的解析方法,刚好想到Delphi里可以利用反射机制和泛型的优势,这里把方法分享出来。代码如下:

function DBRowToArray<T>(const ADBRows: ISQLDBRows): TArray<T>;
const
  V_DataBufferLen = 128;
var
  AStepIndex, ABufferCount: Integer;
  ADataObj: TObject;
  APropList: PPropList;
  APropInfo: PPropInfo;
  APropName, APropString: string;
  I, Count: Integer;
begin
  APropList := nil;
  AStepIndex := 0;
  ABufferCount := 1;
  try
    SetLength(result, V_DataBufferLen);
    while ADBRows.Step do
    begin
      ADataObj := T.Create;
      if APropList = nil then
        Count := GetPropList(ADataObj, APropList);
      if APropList <> nil then
      begin
        for I := 0 to Count - 1 do
        begin
          APropInfo := APropList^[I];
          APropName := GetPropName(APropInfo);
          try
            if ADBRows.ColumnIndex(S2U(APropName)) < 0 then
              Continue;
            case APropInfo.PropType^.Kind of
              tkInteger, tkFloat, tkEnumeration:
                begin
                  SetPropValue(ADataObj, APropName, ADBRows.Column[StringToUTF8(APropName)]);
                end;
              tkString, tkUString:
                begin
                  APropString := ADBRows.Column[StringToUTF8(APropName)];
                  SetPropValue(ADataObj, APropName, APropString);
                end;
              tkInt64:
                begin
                  SetInt64Prop(ADataObj, APropName, ADBRows.Column[StringToUTF8(APropName)]);
                end;
            end;
          except
            on E: Exception do
            begin
              WriteLog('TWebAPIServer.DBRowToArray', Format('T:%s  PropName:%s   E:%s',
                [T.ClassName, APropName, E.Message]));
            end;
          end;
        end;
      end;
      result[AStepIndex] := ADataObj as T;
      Inc(AStepIndex);
      if AStepIndex = ABufferCount * V_DataBufferLen then
      begin
        Inc(ABufferCount);
        SetLength(result, V_DataBufferLen * ABufferCount);
      end;
    end;
    SetLength(result, AStepIndex);
  finally
    if APropList <> nil then
      FreeMem(APropList);
  end;
end;

使用方法如下:

var 
  ADepartItems: TArray<TIMCDepartItem>;
ADepartItems := DBRowToArray<TIMCDepartItem>(ADBRows);