实现通用的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);