【问题标题】:How to clone a dataset structure (TFDQuery) in Delphi 10?如何在 Delphi 10 中克隆数据集结构(TFDQuery)?
【发布时间】:2017-11-01 00:41:39
【问题描述】:

谁能帮我在运行时克隆一个 TFDQuery?我在 Delphi Tokyo 编码,我有一个带有 TFDQuery 的数据模块,我在设计时使用字段编辑器定义了所有字段属性,这样我的 DBGrid1 指向这个数据集的数据模块,所有列的格式都正确(显示名称、宽度、格式、顺序)。在运行时,我需要创建 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 没有显示源数据集的列顺序、标签和格式,为什么?

第三种方法 - 逐一复制字段定义 - 无效

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;

 ...

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

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

提前谢谢大家!

【问题讨论】:

  • 然后存储和恢复数据库网格列。
  • 试试CopyDataSet[coStructure]
  • @Jason,当您重新分配其数据源时,数据库网格会丢失列信息。代码like this 可以帮助您保留它。底层数据集的字段定义只是其中的一部分。
  • @Jason,谢谢!我尝试了您建议的命令:vdataset.CopyDataSet(Dtmodule.FDQueryDados, [coStructure]) 但它引发了错误:[FireDAC][Phys][Ora]-306。命令文本不能为空。
  • @Vitoria,感谢代码链接。我试过了,它部分解决了!!我可以从原始 Dbgrid1 中恢复列定义的某些部分,例如 order 和可见的可见列,但是它没有恢复显示名称、显示格式。请记住,我已经在 TFDQuery 字段中进行了定义,并且该数据集与链接到 DBgrid 的 Tdatamodule 相关联。我还没有定义 DBgrid Columns !感谢您的帮助!

标签: delphi dataset clone


【解决方案1】:

当您使用字段编辑器进行查询时,您创建的是字段而不是字段定义。据我所知,FieldDefs 在创建组件时与 FieldsCollection 保持同步(或者可能不是 100% 确定打开)。 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 问题。我认为这是我最初从以下位置获取代码的地方: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 方法所迷惑。帮助使它看起来像是可以复制字段结构。当它真的为任何匹配的字段名称复制当前字段“值”时。

【讨论】:

  • +1,但是,如果需要复制 TFloatField.DisplayFormat 等属性,则应检查 NewField.Datatype 并相应地进行转换。 TFloatField(NewField).DisplayFormat := TFloatField(Field).DisplayFormat
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 1970-01-01
相关资源
最近更新 更多