8

正確さ:私のコードは、ランタイムコマンドの結果として作成されたDelphi XE(プロパティセットでにTClientDataset接続されている)の非物理フィールドを更新しようとしています。TSQLQuerySQLOpen

TClientDataset接続されてTDatasetProviderいるに接続TSQLQueryされていTSQLConnectionます。これらのオブジェクトの最初の3つは、いくつかのプロジェクトの多くの場所で使用しているライブラリのいくつかのクラスにカプセル化されています。これらのクラスは実行時にこれらの3つのオブジェクトを作成し、これらのトリプレットの多くを持っているので必要な、大量の反復コードを排除します。

非常に一般的には、のプロパティでTClientDatasetSQLを指定し、を呼び出すことによって、データベースからをロードします。のは、ieへのこの呼び出しを介して作成されます。の前には存在しません。SQLTSQLQueryOpenTClientDataSetFieldsTClientDatasetOpenOpen

に生成された3つのフィールドTClientDatasetが非物理的である状況で問題が発生しました。つまり、SQLはそれらを生成するために計算を行います。残念ながら、ではTClientDataset、これらの3つのフィールドは物理フィールドと同じように作成されます。それらFieldKindfkData(理想的にはfkInternalCalc)、CalculatedプロパティはFalse(理想的にはTrue)、そしてそれらのProviderFlagsインクルードpfInUpdate(理想的にはそうではない)です。当然のことながら、例外を実行するときが来るとApplyUpdatesTClientDataset例外がスローされます...

Project XXX.exe raised exception class TDBXError with message
SQL State: 42S22, SQL Error Code: 207 Invalid column name 'Received'.
SQL State: 42S22, SQL Error Code: 207 Invalid column name 'Issued'.
SQL State: 42S22, SQL Error Code: 207 Invalid column name 'DisplayTime'.

のイベントハンドラでこれらのフィールドのpfInUpdateフラグをクリアすることで、このエラーを回避できます。ただし、このソリューションでは、特定のフィールド名が上記の汎用クラスにあるこの関数に認識されている必要があるため、コードの一般性が損なわれます。TDatasetProviderOnUpdateData

私が探しているのは、これらのフィールドの計算された性質をイベントハンドラー関数に通知する一般的な手段です。

呼び出し後にFieldKindorCalculatedプロパティを(fkInternalCalcそれぞれTrueに)変更することはできません。これにより、例外メッセージが生成されるためです。また、まだ存在しないため、呼び出し前にこれらのプロパティを変更することはできません。OpenWorkCDS: Cannot perform this operation on an open datasetOpenFields

後でこれらのプロパティpfInUpdateからフラグを削除できますが、これはイベントハンドラーに到着する「デルタ」に渡されません。また、フィールドのプロパティを設定してみました。繰り返しますが、これはDeltaデータセットに渡されません。FieldProviderFlagsOpenTClientDatsetOnUpdateDataFieldDefs.InternalCalcField

ですから、私が試したすべてのシグナリングのアイデアはうまくいきませんでした。新しいアイデアや別のアプローチに感謝します。

私が遭遇したすべてのインターネット検索結果(Cary Jensenの優れた記事を含む)は、私の状況に当てはまらない設計時またはSQL以外で生成されたセットアップを扱っています。

4

2 に答える 2

5

クラスにメカニズムを作成して、更新プロセスで無視する個々のフィールドのProviderFlagsを事前に構成できます。

あなたの質問へのコメントによると、クラスに新しいメソッドを作成して内部のClientDataSetを開くことをお勧めします。すべての魔法は、このメソッド内で行われます。

まず、簡単なメカニズムの1つは、無視するすべてのフィールドを一覧表示する新しいTStringListプロパティを含めることです。これは、名前で照合します。これを自由に採用するか、新しいより良いメカニズムを作成してください。重要なことは、そのように構成するフィールドを識別できることです。

type
  TMyClass = class
    // all your current class here
  private
    FUpdateIgnoredFields: TStringList;
  public
    property UpdateIgnoredFields: TStringList read FUpdateIgnoredFields write SetUpdateIgnoredFields;
    //don't forget to create this in your constructor, free it in the destructor
    //and Assign any new value in the SetUpdateIgnoreFields method, as usual.
    procedure OpenInnerCDS; //the magic goes here
  end;

procedure TMyClass.OpenInnerCDS;
var
  FieldName: string;
  AFieldToIgnore: TField;
begin
  //opens the inner cds, but before that, configures the update-ignored  
  //fields in the underlying dataset
  //Let's call it InnerBaseDataSet;
  FInnerBaseDataSet.Open; //this opens the DataSet and creates all the fields for it.
  try
    for FieldName in FUpdateIgnoredFields do
    begin
      AFieldToIgnore := FInnerBaseDataSet.FindField(FieldName);
      if Assigned(AFieldToIgnore) then
        AFieldToIgnore.ProviderFlags := AFieldToIgnore.ProviderFlags - [pfInUpdate, pfInWhere];
    end;
    //now, let's open the ClientDataSet;
    FInnerClientDataSet.Open;
  finally
    //I suggest no matter what happens, always close the inner data set
    //but it depends on how the CDS->Provider->DataSet interaction is configured
    FInnerBaseDataSet.Close;
  end;
end;

//the way you use this is to replace the current ClientDataSetOpen with something like:

var
  MyInsance: TMyClass;
begin
  MyInstance := TMyInstance.Create();  //params
  try
    //configuration code here
    //MyInstance.InnerCDS.Open;  <-- not directly now
    MyInstance.UpdateIgnoreFields.Add('CALCULATED_SALARY');
    MyInstance.OpenInnerCDS;
    //use the CDS here.
    MyInstance.InnerCDS.ApplyUpdates(-1); //safely apply updates now.
  finally
    MyInstance.Free;
  end;
end;

アイデアとしてそれを取りなさい。

私はここにすべてのコードを書きました、多分構文が間違っています、しかしそれは全体の考えを示しています。

于 2012-11-22T07:13:04.963 に答える
1

CDSで対応するオプションのパラメーターを設定することにより、ProviderFlags(およびその他のいくつかのプロパティ)をクライアントからプロバイダー(デルタ)側に渡すことができます。IncludeInDeltaパラメータを設定することを忘れないでください

于 2012-11-22T12:04:16.237 に答える