13

Delphiでクエリを使用してデータを取得していますが、実行する前に計算フィールドをクエリに追加したいと思います。計算フィールドはクエリだけでなくコードの値も使用しているため、SQLで計算することはできません。

イベントを添付して実際に計算を行うことができることは知ってOnCalcFieldsいますが、問題は、計算フィールドを追加した後、クエリに他のフィールドがないことです...

掘り下げてみると、すべてのフィールド定義が作成されていますが、実際のフィールドは作成されているだけであることがわかりました

if DefaultFields then
    CreateFields

デフォルトのフィールドが指定されています

procedure TDataSet.DoInternalOpen;
begin
    FDefaultFields := FieldCount = 0;
    ...
end;

これは、フィールドを追加すると、追加したフィールドのみが取得されることを示します。

クエリのすべてのフィールドを、追加したフィールドと同様に使用したいと思います。

これは可能ですか、それとも使用しているすべてのフィールドを追加する必要がありますか?

4

4 に答える 4

15


コードで最初にすべてのフィールドを作成してから、計算されたフィールドを追加することを妨げるものは何もありません。

「ハッキングされたタイプ」を使用して、保護されたCreateFieldsを使用することができます。

type
  THackQuery = class(TADOQuery)
  end;
[...]
  MyQuery.FieldDefs.Update;
  THackQuery(MyQuery).CreateFields;

またはCreateFieldsからコードを借用します。

  MyQuery.FieldDefs.Update;
  // create all defaults fields
  for I := 0 to MyQuery.FieldDefList.Count - 1 do
    with MyQuery.FieldDefList[I] do
      if (DataType <> ftUnknown) and not (DataType in ObjectFieldTypes) and
        not ((faHiddenCol in Attributes) and not MyQuery.FIeldDefs.HiddenFields) then
        CreateField(Self, nil, MyQuery.FieldDefList.Strings[I]);

次に、計算フィールドを作成します。

  MyQueryMyField := TStringField.Create(MyQuery);
  with MyQueryMyField do
  begin
    Name := 'MyQueryMyField';
    FieldKind := fkCalculated;
    FieldName := 'MyField';
    Size := 10;
    DataSet := MyQuery;
  end;
于 2010-03-26T17:55:21.313 に答える
4

計算フィールドに加えて、すべてのフィールドを追加する必要があります。

フィールドを追加したら、データセットに必要なすべてのフィールドを追加する必要があります。

Delphiは、この永続フィールドを動的フィールドと呼びます。すべてのフィールドは永続的または動的です。残念ながら、両方を混在させることはできません。

ドキュメントから、注意すべきもう1つのことは

永続フィールドコンポーネントリストはアプリケーションに保存され、データセットの基礎となるデータベースの構造が変更されても変更されません。

したがって、後でテーブルにフィールドを追加する場合は、コンポーネントに新しいフィールドを追加する必要があることに注意してください。フィールドの削除についても同じです。

永続フィールドが本当に必要ない場合は、別の解決策があります。計算フィールドを表示するグリッドまたはコントロールでは、カスタム描画できます。たとえば、多くのグリッドコントロールにはOnCustomDrawイベントがあります。そこで計算を行うことができます。

于 2010-03-26T14:42:49.723 に答える
3

Delphiには、自動生成されたフィールドと計算されたフィールドを組み合わせるオプションがあります:Data.DB.TFieldOptions.AutoCreateModeタイプTFieldsAutoCreationModeの列挙。このようにして、実行時に計算フィールドを追加できます。フランソワは、実行時にフィールドを追加する方法を彼の回答に書いています。

TFieldsAutoCreationModeのさまざまなモード:

  • acExclusive

    永続フィールドがまったくない場合は、自動フィールドが作成されます。これがデフォルトのモードです。

  • acCombineComputed

    自動フィールドは、データセットに永続フィールドがない場合、または計算された永続フィールドのみがある場合に作成されます。これは、設計時に永続的な計算フィールドを作成し、データセットに自動データフィールドを作成させるための便利な方法です。

  • acCombineAlways

    永続フィールドがない場合、データベースフィールドの自動フィールドが作成されます。

于 2017-09-27T08:24:33.487 に答える
2

実行時に計算されるフィールド名を知っている場合は、そのようなものを使用できます。

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;
于 2010-03-26T21:47:40.623 に答える