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;

但是每个表的 fieldValues 都不同,因此您可能会使用 fieldvalues (即它们的索引号)使应用程序崩溃(几乎可以肯定)。

你如何克服这一点?是否可以分别记录每个表?

4

1 回答 1

0

正如我在评论中提到的,我没有 Accuracer,但认为发布一种进行客户端日志记录的通用方法可能会有所帮助,该方法可以捕获一个或多个字段的值并用于尽可能多的数据集你需要。您可以在 ACRDatabase1AfterInsertRecord 处理程序中使用它的一部分,因为它的 Sender 参数似乎标识了新行已插入的数据集。

如您所见,有一个 LogFields 过程可以包含在您喜欢的任何数据集的 AfterInsert 处理程序中,这会调用一个单独的 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 过程的要点之一是它有助于将客户端日志记录扩展到现有数据集记录中的更改。如果您在启动时生成此列表并将其保存在某处,您可以在数据集的 BeforePost 事件中使用它来获取字段的当前值和以前的值(使用其 Value 和 OldValue 属性),将它们保存在另一个StringList 并将它们记录在 AfterPost 事件中。当然,如果您对来自多个数据集的这些值使用公共存储,则需要确保一个数据集的 AfterPost 在任何其他数据集的 BeforePost 之前触发,或者完全在 BeforePost 中进行日志记录(必须在 Before- 和 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;

Otoh,如果出于某种原因(我不能立即想到为什么我们想要但没关系)我们只是想检查我们作为 AnObject 参数传递的内容是否是特定对象,我们可以省略强制转换和做就是了

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

无论我们作为 AnObject 参数传递的实际类是什么,这种相等性检查都有效,因为所有其他类都是 AnObject 声明的类(即 TObject)的后代。

于 2014-10-29T13:37:16.027 回答