实现通用的ISQLDBRows转换为Object数组的方法
最近在使用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);