【问题标题】:FDQuery (SQL) results to array of records in DelphiFDQuery (SQL) 结果到 Delphi 中的记录数组
【发布时间】:2014-11-26 18:25:12
【问题描述】:

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

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

type
  TPersonList = array of TPerson;

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

var Persons: TPersonList;
begin
Persons[0].id := FDQuery1.FieldByName('id').AsInteger;
....
....
....
end;

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

while not FDQuery.eof do begin
    ...
    Persons[i] := FDQuery1[i];
    ...
end;

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

【问题讨论】:

  • 不,没有办法直接这样做;您必须编写自己的函数来填充并返回记录。不过,我不确定您为什么要这样做;您可以直接访问数据,或将其放入允许您索引、搜索、编辑等操作的 TClientDataSet 中。
  • 我个人经常将记录作为 BLOB 存储到缓存中(因为完全相同的流通过 TCP 传输)。
  • 真正的大问题是,为什么当您已经拥有一个包含您需要的所有信息的 Dataset 对象时,您还需要在此结构中存储一个 db 记录集吗? ..
  • @kobik,我一拿到数据就在做。数据集后代(并且将会)比exact purpose 集合慢得多。除了性能之外,我还缺少在不移动 heavy-weight 光标的情况下访问任何记录的能力(我使用的许多控件都是基于虚拟范例的,这样的操作会很疯狂)。
  • @TLama,我不是说“你不应该这样做”。将数据集保存在硬编码的数组记录结构中(可能不是客户端数据集)需要有充分的理由。

标签: arrays delphi record firedac


【解决方案1】:

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

您可以为此使用记录方法,但这会使使用缓存的字段引用不太优雅,因此我建议使用单独的专用初始化程序类。这可以使用缓存的字段引用来提高效率:

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;

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

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;

正如您所看到的,这不是大量的工作(比显式初始化 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;

qryPersons 是一些返回人员行的 TFDQuerypersons 是您的 TPerson 记录数组(当然,大小/dminesioned 适当)

通过使用 TDataset 基类(TFDQuery 最终派生自该基类),您可以在需要初始化 TPerson 的任何地方使用此初始化程序类> 来自 TDataset 后代,无论是 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;

注意:这些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;

【讨论】:

    猜你喜欢
    • 2023-03-23
    • 1970-01-01
    • 2017-12-04
    • 1970-01-01
    • 2014-07-31
    • 1970-01-01
    • 1970-01-01
    • 2013-05-09
    • 1970-01-01
    相关资源
    最近更新 更多