如何在Delphi 10中克隆数据集结构(TFDQuery)?

时间:2017-11-01 00:41:40

标签: delphi dataset clone

有人可以帮我在运行时克隆TFDQuery吗?我在Delphi东京编码,我有一个带有TFDQuery的Datamodule,我在设计时使用Fields Editor定义了所有字段属性,这样我的DBGrid1指向这个数据集的Datamodule,所有列都正确格式化(显示名称,宽度,格式,顺序)。在运行期间,我需要创建TFDQuery,TDatamodule的新实例,并使用Dbgrid1链接这些新对象。我需要这个新的TFDQuery与设计时定义的现有TFDQuery相同,以保持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没有收到现有FDQquery的字段定义。打开vdataset后,DBGrid1没有显示源数据集的列序列,标签和格式,为什么?

第3种方法 - 逐个复制字段定义 - 无法正常工作

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;

 ...

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

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

提前谢谢大家!

1 个答案:

答案 0 :(得分:2)

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

请注意,循环和创建的项目是“Fields”,但我们使用临时的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问题。我认为这是我最初使用我的代码的地方:Is there some better way to copy all DataSet Fields and their properties to another DataSet?

以下是另一篇使用类似方法的博文:How to: Clone TField and TDataset fields structure

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