2017-11-01 5 views
1

実行時にTFDQueryをクローンするのに助けてくれる人はいますか?私はDelphi Tokyoでコーディングしています。TFDQueryを持つDatamoduleがあり、デザイン時にFields Editorを使用してすべてのフィールドプロパティを定義しました。このように、このデータセットのDatamoduleを指す私のDBGrid1は、名前、幅、フォーマット、順序を表示)。実行時にTFDQuery、TDatamoduleの新しいインスタンスを作成し、これらの新しいオブジェクトをDbgrid1にリンクする必要があります。この新しいTFDQueryは、DBgrid1を同じ表示名、表示幅、および表示形式でデザイン時に保持するために、設計時に定義された既存のTFDQueryと同一である必要があります。Delphi 10でデータセット構造(TFDQuery)をクローンする方法は?

**第一のアプローチ: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; 

Althought 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; 

... 

を動作しませんでした、それが実行されても開けvdataset後、DBGrid1ソースデータセットの列シーケンス、ラベル、およびフォーマットを表示していませんでした。

上記のコードを修正するか、または既存のデータセットから新しいデータセットフィールド定義をコピーする適切なメソッドを実装することに感謝します。

ありがとうございました!

+0

DBグリッド列も同様に格納して復元します。 – Victoria

+0

'' [coStructure] 'を使って 'CopyDataSet'を試してください – Jason

+0

@ Jason、データグリッドを再割り当てすると、DBグリッドは列情報を失います。コード[このような](https://pastebin.com/rN4gG5w0)はあなたがそれを保つのを助けることができます。基本となるデータセットのフィールド定義は、1つの部分に過ぎません。 – Victoria

答えて

1

Fieldsエディタを使用して、FielddefsではなくFieldsを作成しているクエリの場合。私がFieldDefsがFieldsCollectionと同期しているのは、コンポーネントが作成されたとき(または100%確実に開かれていないとき)に保持されることがわかります。 Display *プロパティはFieldDefオブジェクトでは使用できません。FieldDefオブジェクトにのみ存在します。構造体をコピーするには、フィールドを反復処理する必要があります。私たちが使う方法は以下の通りです。

ループと作成される項目は「フィールド」ですが、コードを簡単にするために一時的なFieldDefオブジェクトを使用しています。 TFieldDef.CreatFieldは、正しいタイプのフィールド、すなわちTIntegerFieldとTSt​​ringFieldを取得するためのクラスファクトリメソッドとして機能します。また、計算フィールドを使用している場合は、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?

そして、ここで同様のアプローチを使用しています一つの他のブログ記事です:またTDataSet.CopyField法にだまされませんHow to: Clone TField and TDataset fields structure

私は、これは私が最初から私のコードを取ったところだと思います。ヘルプによって、フィールド構造をコピーできるように見えます。実際には、一致するフィールド名に現在のフィールド "値"をコピーします。

+1

+1しかし、TFloatField.DisplayFormatなどのプロパティをコピーする必要がある場合は、NewField.Datatypeをチェックし、それに応じてキャストする必要があります。 'TFloatField(NewField).DisplayFormat:= TFloatField(Field).DisplayFormat' –

関連する問題