0

次のようなコードは、(アプリケーション全体からの) すべてのテーブル挿入をログに記録します。

procedure TForm1.ACRDatabase1AfterInsertRecord(Sender: TACRDataSet;
  const TableName: WideString; const FieldValues: TACRArrayOfTACRVariant);
begin
if (AnsiUpperCase(TableName) = AnsiUpperCase(LogTable.TableName)) then
 Exit;
 if (Sender is TACRTable) then
 LogTable.Insert();
 LogTable.FieldByName('EventTime').AsDateTime := Now;
 LogTable.FieldByName('TableName').AsString := TableName;
 LogTable.FieldByName('EventType').AsString := 'Insert ';
 LogTable.FieldByName('Whatever').AsString := FieldValues[4].AsString;
 LogTable.Post();
end;

ただし、フィールド値はテーブルごとに異なるため、フィールド値、つまりインデックス番号を使用してアプリケーションを (ほぼ確実に) クラッシュさせる可能性があります。

これをどのように克服しますか?各テーブルを個別にログに記録することは可能ですか?

4

1 に答える 1

0

コメントで述べたように、私は Accuracer を持っていませんが、1 つ以上のフィールドの値をキャプチャし、できるだけ多くのデータセットに使用できる、クライアント側のログ記録を行う一般的な方法を投稿すると役立つかもしれないと考えました。あなたが必要です。Sender パラメーターは、新しい行が挿入されたデータセットを識別するために表示されるため、ACRDatabase1AfterInsertRecord ハンドラーでその一部を使用できる場合があります。

ご覧のとおり、任意のデータセットの AfterInsert ハンドラーに含めることができる LogFields プロシージャがあり、これは別の GetFieldsToLog プロシージャを呼び出して、特定のデータセットをログに記録するフィールドの名前を一時的な StringList に追加します。 . 特定のデータセット セットのニーズに合わせて調整する必要があるのは、GetFieldsToLog プロシージャだけです。

procedure TForm1.GetFieldsToLog(ADataSet : TDataSet; FieldList : TStrings);
begin
  FieldList.Clear;
  if ADataSet = AdoQuery1 then begin
    FieldList.Add(ADataSet.Fields[0].FieldName);
  end
  else
    // obviously, deal with other specific tables here
end;

procedure TForm1.LogFields(ADataSet : TDataSet);
var
  TL : TStringList;
  i : Integer;
  ValueToLog : String;
begin
  TL := TStringList.Create;
  try
    GetFieldsToLog(ADataSet, TL);
    for i := 0 to TL.Count - 1 do begin
      ValueToLog := ADataSet.FieldByName(TL[i]).AsString;
      //  do your logging here however you want
    end;
  finally
    TL.Free;
  end;
end;

procedure TForm1.ADOQuery1AfterInsert(DataSet: TDataSet);
begin
  LogFields(DataSet);
end;

ところで、別の GetFieldsToLog プロシージャを持つポイントの 1 つは、クライアント側のログ記録を既存のデータセット レコードの変更に拡張するのに役立つことです。起動時にこのリストを生成してどこかに保存すると、データセットの BeforePost イベントでそれを使用して、フィールドの現在および以前の値を取得し (その Value および OldValue プロパティを使用)、それらを別のイベントに保存できます。 StringList に保存し、AfterPost イベントに記録します。もちろん、複数のデータセットからのこれらの値に共通のストアを使用している場合は、1 つのデータセットの AfterPost が他のデータセットの BeforePost の前に起動するようにするか、完全に BeforePost 内でログを記録する必要があります ( Before-Post と AfterPost の間に古いフィールド値と現在のフィールド値を保存するのは面倒です。AfterPost ですべてを行う方がよいでしょう。

OldValue を取得するには、それを正しく実装するために特定のデータセット タイプが必要であることに注意してください。ただし、私が遭遇したすべてのタイプのデータセットがそうであるとは限らないため、確認する必要があります。

ところで#2、このような手順があるとします

procedure TForm1.DoSomething(AnObject : TObject);

次に、「if AnObject is ...」を使用して、このようなことを行うことができます

var
  AnAdoQuery : TAdoQuery;
begin
  if AnObject is TAdoQuery then begin
    // First, use a cast to assign Sender to the local AnAdoQuery variable
    AnAdoQuery := TAdoQuery(AnObject);
    // Then, we can do whatever we like with it, e.g.
    Caption := AnAdoQuery.Name;
  end;
end;

おお、なんらかの理由で (理由はすぐにはわかりませんが気にしないでください)、AnObject パラメーターとして渡されたものが特定のオブジェクトであることを確認したいだけの場合は、キャストを省略してただする

  if AnObject = AdoQuery1 then 
    ShowMessage('Received AdoQuery1');

この等価チェックは、AnObject パラメータとして渡された実際のクラスに関係なく機能します。これは、他のすべてのクラスが AnObject の宣言されたクラス、つまり TObject の子孫であるためです。

于 2014-10-29T13:37:16.027 に答える