这样的代码记录所有表插入(来自整个应用程序):
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不同,所以你可能会崩溃 应用程序(几乎可以肯定)使用字段值,即它们的索引号。
你怎么克服这个?是否可以单独记录每个表?
答案 0 :(得分:0)
正如我在评论中提到的,我没有Accuracer,但认为它可能会有所帮助 发布一个执行客户端日志记录的通用方法,它可以捕获值 一个或多个字段,可用于所需数量的数据集。你可能 能够在ACRDatabase1AfterInsertRecord处理程序中使用它的一部分作为其发件人 参数似乎用于标识已插入新行的数据集。
如您所见,有一个LogFields过程可以包含在AfterInsert中 您喜欢的任何数据集的处理程序,这会调用一个单独的GetFieldsToLog过程 添加字段的名称以将给定数据集记录到临时StringList。它' S 只有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内(必须存储旧的和当前的字段值 之前和之后的事情很混乱,在AfterPost中做所有事情会更好, 但不幸的是,AfterPost发生时OldValue已经过时了。
请注意,获取OldValue需要特定的数据集类型才能正确实现 它。但是,并非我所遇到的所有类型的数据集都需要检查。
Btw#2,假设您有这样的程序
procedure TForm1.DoSomething(AnObject : TObject);
那么你可以使用"如果AnObject是......"做这样的事情
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。