4

質問のタイトルにあるように、計算フィールドの使用方法について同僚と議論しています。私の知る限り、実行時に計算フィールドをクエリに追加するという質問に対するフランソワの回答のように、計算フィールドは実行時に作成されます。同じ質問には、sabri.arslan からの別の回答があり、既存のフィールドを計算されたフィールドに変更することを提案しています (以下のコード)。

var
 initing:boolean;

procedure TSampleForm.dsSampleAfterOpen(
  DataSet: TDataSet);
var
 i:integer;
 dmp:tfield;
begin
if not initing then
 try
  initing:=true;
  dataset.active:=false;
  dataset.FieldDefs.Update;
  for i:=0 to dataset.FieldDefs.Count-1 do
  begin
   dmp:=DataSet.FieldDefs.Items[i].FieldClass.Create(self);
   dmp.FieldName:=DataSet.FieldDefs.Items[i].DisplayName;
   dmp.DataSet:=dataset;
   if (dmp.fieldname='txtState') or (dmp.FieldName='txtOldState') then
   begin
     dmp.Calculated:=true;
     dmp.DisplayWidth:=255;
     dmp.size:=255;
   end;
  end;
  dataset.active:=true;
 finally
  initing:=false;
 end;
end;

procedure TSampleForm.dsSampleAfterClose(
  DataSet: TDataSet);
var
 i:integer;
 dmp:TField;
begin
if not initing then
begin
 for i:=DataSet.FieldCount-1 downto 0 do
 begin
  dmp:=pointer(DataSet.Fields.Fields[i]);
  DataSet.Fields.Fields[i].DataSet:=nil;
  freeandnil(dmp);
 end;
 DataSet.FieldDefs.Clear;
end;
end;

procedure TSampleForm.dsSampleCalcFields(
  DataSet: TDataSet);
var
 tmpdurum,tmpOldDurum:integer;
begin
  if not initing then
    begin
      tmpDurum := dataset.FieldByName( 'state' ).AsInteger;
      tmpOldDurum:= dataset.FieldByName( 'oldstate' ).AsInteger;
      dataset.FieldByName( 'txtState' ).AsString := State2Text(tmpDurum);
      dataset.FieldByName( 'txtOldState' ).AsString := State2Text(tmpOldDurum);
    end;
end;

procedure TSampleForm.btnOpenClick(Sender: TObject);
begin
 if dsSample.Active then
   dsSample.Close;
 dsSample.SQL.text:='select id,state,oldstate,"" as txtState,"" as txtOldState from states where active=1';
 dsSample.Open;
end;

この変更は、指定された TField の未知の動作につながると思います。ランタイムでデータセット フィールドを計算フィールドに変更しても安全ですか? これにより、どのような問題が発生する可能性がありますか?

LE: これは質問です。その目的は、実行時にデータセットに計算フィールドを追加するための優れた方法を示すことです。そして、はい、実行時に計算フィールドを追加するのは悪い設計です。

LE2: これは、「このようにしないでください」の単なる例です。議論として、これを行った後の議論でフィールドの動作は何かを尋ねました。そのフィールドはどのように機能しますか?

4

3 に答える 3

3

いいえ、それは良い習慣ではありません。コードが複雑であるという単純な事実は、そのような慣行を避けるべきであることを示唆しています。誰かがすでに KISS の原則を参照しており、私はそれに同意します。

特に、データセットを 2 回開かなければならないという単純な事実だけで、私はこの慣行を嫌うようになります。

さらに、フィールドの性質をデータから計算に変更すると、データセットが内部レコード表現 (データセットがレコード バッファと呼ぶもの) でフィールドを編成する方法が変更されます。このような表現は、データセットの実装ごとに大きく異なる場合があります。質問は特定のデータセットを特定しなかったため、動作の変更は(一般的に)次のとおりです。

  1. データ フィールドは、基礎となるデータベース クライアントに属する構造体に値を格納します。計算フィールドは、その値を永続的でないバッファーに格納します。
  2. データセットを開くときに、データフィールドをデータベース クライアントの対応する構造にバインドする、フィールド バインドという名前のプロセスがあります。このバインディングが失敗すると、データセットは通常例外を発生させます。計算フィールドは、内部フィールド バッファを使用して値を格納するため、このプロセスに関与しません。
  3. フィールドは、計算されたフィールドになった後、慣れ親しんだ方法でOnCalcFieldsイベントの実行中に値を受け入れます。データセットの実装によっては、フィルタリングの目的で使用されない場合があります。

ただし、特定のデータセットの実装は、その目的と機能に応じて、他の結果をもたらす可能性があります。

于 2013-08-13T14:55:08.773 に答える
0

TField は、データベース列にマップされるか、またはマップされず、計算によって導出されます。これは設計時に設定する必要があります。実行時にこれを変更しようとすると、IMO の設計が不適切であり、多くの潜在的な頭痛の種になる可能性があります。

于 2013-08-13T10:13:48.300 に答える