FDQuery(SQL)导致Delphi中的记录数组

Gem*_*Gem 4 arrays delphi record firedac

有没有办法直接将FDQuery结果复制到记录数组?所以这是声明的类型:

type
  TPerson = record
    id: integer;
    name: string;
    surname: string;
  end;

type
  TPersonList = array of TPerson;
Run Code Online (Sandbox Code Playgroud)

我有SQLite DB和列id, namesurname.通常我应该像这样向该数组添加值:

var Persons: TPersonList;
begin
Persons[0].id := FDQuery1.FieldByName('id').AsInteger;
....
....
....
end;
Run Code Online (Sandbox Code Playgroud)

但有没有更好/更紧凑的方法来做到这一点?一些功能如:

while not FDQuery.eof do begin
    ...
    Persons[i] := FDQuery1[i];
    ...
end;
Run Code Online (Sandbox Code Playgroud)

也许直接或在循环中?或者我应该创建一些功能来做到这一点?因为我有很多列,并且有许多不同的记录类型,它们具有不同的结构,但具有类似于db的精确结构.

Del*_*ics 7

没有简单的方法可以直接执行此操作,但您可以使用一些技术来提高源和运行时性能的效率.一种方法可能是创建一个简单的帮助器来初始化给定数据集中适当类型的新值.

你可以使用一个记录方法,但这会使缓存的字段引用不那么优雅,所以我建议一个单独的,专用的初始化类.这可以使用缓存的字段引用来提高效率:

type
  TPersonFDInitialiser = class
  private
    fldID: TIntegerField;
    fldName: TStringField;
    fldSurname: TStringField;
    function get_NewValue: TPerson;
  public
    constructor Create(const aSource: TDataset);
    property NewValue: TPerson read get_NewValue;
  end;
Run Code Online (Sandbox Code Playgroud)

在构造函数中缓存字段引用可避免每次检索每条记录的值时都必须按名称查找它们.对字段数据类型使用适当的类允许直接访问每个字段值而无需任何转换:

constructor TPersonFDInitialiser.Create(const aSource: TDataset);
begin
  inherited;

  fldID      := aSource.FieldByName('id') as TIntegerField;
  fldName    := aSource.FieldByName('name') as TStringField;
  fldSurname := aSource.FieldByName('surname') as TStringField;
end;


function TPersonFDInitialiser.get_NewValue: TPerson;
begin
  result.ID      := fldID.Value;
  result.Name    := fldName.Value;
  result.Surname := fldSurname.Value;
end;
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,这不是一项大量的工作(比显式初始化1个记录值所需要的多一点),但使得迭代使用更优雅,更快速地编写,看起来像这样:

recno := 0;
init := TPersonFDInitialiser.Create(qryPersons);
try
  while NOT qryPersons.EOF do
  begin
    persons[recno] := init.NewValue;

    qryPersons.Next;
    Inc(recno);
  end;

finally
  init.Free;
end;
Run Code Online (Sandbox Code Playgroud)

其中qryPersons一些TFDQuery返回的人行和persons你的阵列TPerson记录(尺寸/合适dminesioned,当然)

通过使用TDataset基类(TFDQuery最终从中派生),你可以在任何需要初始化来自TDataset后代的TPerson的地方使用这个初始化类,无论是TFDQuery还是TClientDataset或其他任何东西(只要是那个中的字段)数据集按照书面形式一致地命名,但如果需要,可以在这方面使初始化器更加灵活.这是一个练习).

走得更远

根据您的需要,可以通过许多增强功能来提高此类初始化类的实用性,例如:

// To initialise a one-off, new TPerson value from a data set use a 
//  class function which will internally create an initialiser, obtain 
//   a new TPerson then destroy the initialiser for you:
//
// Note that this will need to be overloaded if it has the same name as
//  the instance method (which must also then be overloaded):

class function TPersonFDInitialiser.NewValue(const aSource: TDataset): TPerson; overload;


// Implement a procedure which will initialise an existing TPerson value
//  (by reference) with values from the current record.
// 
// Again, a class procedure overload could be provided for one-off use
//  taking care of creating and freeing the required initialiser:

class procedure TPersonFDInitialiser.SetPerson(const aSource: TDataset; var aPerson: TPerson); overload;
procedure TPersonFDInitialiser.SetPerson(var aPerson: TPerson); overload;
Run Code Online (Sandbox Code Playgroud)

注意:这些SetPerson方法可以通过get_NewValue实际调用该方法的方式实现,这样您在整个实现中只有一个方法可以实际执行任何值设置.这将消除初始化代码的重复,提高初始化类的可靠性和可维护性:

function TPersonFDInitialiser.get_NewValue: TPerson;
begin
  SetPerson(result);
end;


procedure TPersonFDInitialiser.SetPerson(var aPerson: TPerson);
begin
  aPerson.ID      := fldID.Value;
  aPerson.Name    := fldName.Value;
  aPerson.Surname := fldSurname.Value;
end;
Run Code Online (Sandbox Code Playgroud)