如何在Delphi10中克隆数据集结构(TFDQuery)



有人能帮我在运行时克隆TFDQuery吗?我在Delphi Tokyo中编码,我有一个带有TFDQuery的Datamodule,我在设计时使用fields Editor定义了所有字段属性,通过这种方式,我的DBGrid1指向了这个数据集的一个Datamodule,所有列的格式都正确(显示名称、宽度、格式、顺序)。在运行时,我需要创建TFDQuery、TDatamodule的新实例,并将这些新对象与Dbgrid1链接。我需要这个新的TFDQuery与设计时定义的现有TFDQuerry相同,以便保持DBgrid1与设计时具有相同的显示名称、显示宽度和显示格式!我尝试了以下方法来复制数据集字段定义:

**第一种方法:TFDQuery的方法分配(无效)**

type
TFormDados = class(TForm)
Edit1: TEdit;
Button1: TButton;
DBGrid1: TDBGrid;
Edit2: TEdit;
Label1: TLabel;
Label2: TLabel;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
vconnection : TFDConnection;
vdataset    : TFDQuery;
vdatasource : Tdatasource;
public
{ Public declarations }
end;
var
FormDados: TFormDados;
implementation
{$R *.dfm}
Uses
unitdata;
procedure TFormDados.Button1Click(Sender: TObject);
var
i : integer;
begin
vconnection := TFDConnection.Create(nil);
vconnection.Assign(Dtmodule.FDConGrafico);
vdataset := TFDQuery.Create(nil);
vdataset.Connection  := vconnection;
vdataset.Assign(Dtmodule.FDQueryDados);  // Runtime Error : Cannot assign a TFDQuery to a TFDQuery

第二种方法:将FieldDefs从现有数据集分配给新数据集-不起作用

...
vdataset.FieldDefs.Assign(Dtmodule.FDQueryDados.FieldDefs);
vdataset.sql         := Dtmodule.FDQueryDados.sql;
vdataset.params      := Dtmodule.FDQueryDados.Params;
vdataset.FieldDefs.Update;
vdataset.CreateDataSet;
vdatasource          := Tdatasource.create(nil);
vdatasource.DataSet  := vdataset;
dbgrid1.DataSource   := vdatasource;
vdataset.close;
vdataset.Params[0].Asinteger := strtoint(edit1.Text);
vdataset.Params[1].Asinteger := strtoint(edit2.Text);
vdataset.Open;

尽管Assign方法已经运行,但vdataset没有接收到现有FDQ查询的字段定义。打开vdataset后,DBGrid1没有显示源数据集的列序列、标签和格式,为什么?

第三种方法-逐个复制字段定义-不起作用

for i:=0 to Dtmodule.FDQueryDados.Fields.Count -1 do
begin
with vdataset.FieldDefs.AddFieldDef do
begin
Name        := Dtmodule.FDQueryDados.FieldDefs[i].Name;
Datatype    := Dtmodule.FDQueryDados.FieldDefs[i].DataType;
Displayname := Dtmodule.FDQueryDados.FieldDefs[i].Displayname;
Fieldno     := Dtmodule.FDQueryDados.FieldDefs[i].FieldNo;
end;
end;
vdataset.FieldDefs.Update;
vdataset.CreateDataSet;
vdatasource         := Tdatasource.create(nil);
vdatasource.DataSet := vdataset;
dbgrid1.DataSource := vdatasource;
...

这段代码导致了与方法2相同的结果,即它运行,但在打开vdataset后,DBGrid1没有显示源数据集的列序列、标签和格式。

我感谢您帮助修复上述代码,或者实现将数据集字段定义从一个现有数据集复制到新数据集的正确方法。

提前感谢大家!

当您使用字段编辑器进行查询时,您创建的是字段而不是字段定义。据我所知,当组件创建时(或者可能打开时不是100%确定),FieldDef与FieldsCollection保持同步。Display*属性在FieldDef对象上不可用,它们只存在于Field对象上。当您去复制结构时,您需要迭代字段。我们使用的方法如下。

请注意,循环和创建的项都是"字段",但我们使用了一个临时的FieldDef对象来简化代码。TFieldDef.CreatField用作类工厂方法,以获得正确类型的字段,即TIntegerField与TStringField。此外,如果使用的是计算字段,则需要连接OnCalcField事件。这种方法不能做到这一点。

procedure CopyFieldStructure(Source: TDataSet; Target: TDataset);
{^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^}
var
Field: TField;
NewField: TField;
FieldDef: TFieldDef;
begin
Target.Fields.Clear;
Target.FieldDefs.Clear;
// Cannot perform the next operation on an opened dataset
if Target.State <> dsInactive then
Target.Close;
for Field in Source.Fields do
begin
// We are going to setup the first part in a FieldDef
// that will set us use the CreateField Call in order to
// get the correct subclass of TField created.
FieldDef := Target.FieldDefs.AddFieldDef;
FieldDef.DataType := Field.DataType;
FieldDef.Size := Field.Size;
FieldDef.Name := Field.FieldName;
NewField := FieldDef.CreateField(Target);
NewField.Visible := Field.Visible;
NewField.DisplayLabel := Field.DisplayLabel;
NewField.DisplayWidth := Field.DisplayWidth;
NewField.EditMask := Field.EditMask;
NewField.Calculated := Field.Calculated;
end;
end;

这里有一个类似的StackOverflow问题。我想这就是我最初获取代码的地方:是否有更好的方法将所有数据集字段及其属性复制到另一个数据集?

这里还有一篇使用类似方法的博客文章:如何:克隆TField和TDataset字段结构

也不要被TDataSet.CopyField方法所欺骗。帮助使它看起来可以复制字段结构。当它真正复制任何匹配字段名称的当前字段"值"时。

最新更新