如果用户通过 dbgrid 更改数据,则不会触发 AdoConnection 的 ExecuteCompleted

ExecuteCompleted of AdoConnection is not fired if user changes data via dbgrid

如果我执行类似

的查询
Update Table Set aField = 1 Where tablePk = 1

我可以从AdoConneciton 的ExecuteComplete 事件中获取受影响的记录数(RecordsAffected 参数)。但是,如果我通过 dbgrid 更改数据,则不会触发 ExecuteComplete 事件。

如何在 dbgrid 执行 insert/update/delete 命令后获得受影响的记录数?

我认为没有办法在您进行更新时获取受影响的行数, 通过 TDBgrid 或其他 DB 感知组件(如 TDBNavigator)插入和删除。原因是 DB-aware 控件调用 TDataSet 的 Post 和 Delete 方法,并且这些调用覆盖了 TAdoCustomDataSet 中的 InternalPost 和 InternalDelete。它们的工作方式与通过 TAdoQuery 的 ExecSql 方法执行 SQL 语句的方式完全不同。

根据设计,TDataSet.Post 和 TDataSet.Delete 应该只影响一行,所以如果操作成功,您就会知道只有一行受到影响。

值得注意的是, 有一种方法可以将同一事件处理程序附加到一个数字,尽管对您想要做的事情没有太大帮助 共享 TAdoConnection 的 TAdoCustomDataSet 后代,如以下代码所示:

procedure TForm1.FormCreate(Sender: TObject);
var
  i : Integer;
begin
  for i := 0 to AdoConnection1.DataSetCount - 1 do
    AdoConnection1.DataSets[i].AfterPost := AfterPost;
  AdoQuery1.Open;
  AdoQuery2.Open;
end;

procedure TForm1.AfterPost(DataSet: TDataSet);
var
  Q : TAdoQuery;
begin
  if DataSet is TAdoQuery then begin
    Q := TAdoQuery(DataSet);
    Caption := IntToStr(Q.RowsAffected);
  end
  else
    Caption := 'Post';
end;

当然,如果涉及的数据集已经有自己的事件处理程序, 您将需要一些结构来存储现有的处理程序并链接到 共享处理程序中正确的一个(f.i。TForm1.AfterPost 以上)。

如果您尝试上面的代码并观察当您 post 编辑时会发生什么 从从 TAdoQuery 获取数据的 DBGrid 中,您会不幸地看到,RowsAffected 为零。 那是因为 TAdoQuery 的 FRowsAffected 只在它的时候更新 ExecSql 方法被调用,但数据集操作没有被调用 通过 DBGrid 调用。区别在于 AdoConnection 的 OnExecuteComplete 从用于执行的 Command 对象调用 TAdoQuery 的 ExecSql。从 DBGrid、otoh、call 发起的操作 在其 InternalPost 和 InternalDelete 中与 TAdoCustomDataSet 关联的 RecordSet 对象的方法, 并且不会调用 AdoConnection 的 OnExecuteComplete.

RecordSet 对象有自己的事件集,请参阅 f.i。 RecordSetEvents 在 ADOInt.Pas 中,可以想象您可以为以下各项设置共享事件处理程序 那些与上面的共享 AfterPost 事件示例类似的方式。然而, 如果您想获得,我认为那对您没有任何用处 从调用的 TDataset Insert/Update/Delete 的 RowsAffected 值 DBGrid(或者说连接到它的 TDataSource 的 TDBNavigator)。

我这么说的原因是如果你看一下源代码 TAdoCustomDataSetInternalPost 方法你会看到它包括

  if State = dsEdit then
    UpdateData
  else
  begin
    Recordset.AddNew(EmptyParam, EmptyParam);
    try
      UpdateData;
    except

嵌套的 UpdateData 通过调用

完成它的工作
    Recordset.Update(EmptyParam, EmptyParam);

现在,如果您查看 RecordSet.Update 的 MS 文档,您会看到例如

https://msdn.microsoft.com/en-us/library/ecc2bf09.aspx?f=255&MSPPError=-2147217396

清楚地表明,如果 Update 不影响恰好一条记录,则 引发异常。我想这就是@KenWhite 说的时候想到的 "There will only be a single record updated"。所以如果 RecordSet.Update 成功, 你知道只有一排受到影响。

我没检查过,但是因为 TAdoCustomDataSet.InternalDelete 使用它的 Recordset 反对进行删除,类似的情况可能也是如此。