浏览结果时 FireDac FDQuery 提交更改的数据字段

FireDac FDQuery commit changed DataFields when browsing through results

我有一个 FDQuery 绑定到一个 FDConnection。

我正在使用 DB 数据感知组件在我的表单上显示数据。

每当我使用 FPQuery.Next, .Prior, ... 它会在结果之间浏览。

一切正常。

除非我更改了一个值(例如 John -> Jane),然后使用 FPQuery.Next 获取下一个结果,它保存将更改的值提交给数据库,即使我没有 FDQuery1.CommitUpdates.

有没有办法只在用户按下 nbPost-Button 或使用 FDQuery1.CommitUpdates 而不是在结果之间浏览时保存更改的数据字段?

谢谢!

就像我在评论中所说的那样,标准 TDataset 行为是在导航到另一行之前调用其 .Post 方法来保存对当前行的更改。这发生在 Data.DB.Pas 中的例程 TDataSet.CheckBrowseMode 中,该例程在任何导航操作之前调用。如果不派生自定义 TDataset 后代,则无法更改。

(来自 Data.DB.Pas)

procedure TDataSet.CheckBrowseMode;
begin
  CheckActive;
  DataEvent(deCheckBrowseMode, 0);
  case State of
    dsEdit, dsInsert:
      begin
        UpdateRecord;
        if Modified then Post else Cancel;
      end;
    dsSetKey:
      Post;
  end;
end;

当然,TDataSet 有一个 BeforePost 事件,因此尝试使用它来取消更改可能很诱人;然而,BeforePost 的问题是如何确定调用它的上下文,以便能够判断它是从 CheckBrowseMode 调用的,而不是由于用户单击保存按钮。

解决此问题的简单方法是捕获 DBNavigatorBeforeAction 事件,然后它会在数据集上调用导航操作,这将触发 .Post:

procedure TForm1.DBNavigator1BeforeAction(Sender: TObject; Button:
    TNavigateBtn);
var
  Res : Integer;
  DataSet : TDataSet;
begin
  DataSet := DBNavigator1.DataSource.DataSet;
  case Button of
    nbFirst,
    nbPrior,
    nbNext,
    nbLast: begin
      if DataSet.State in [dsEdit, dsInsert] then begin
        Res := MessageDlg('The current row has unsaved changes.  Abandon them?', mtWarning, [mbYes, mbNo], 0);
        if Res = mrYes then
          DataSet.Cancel
        else
          DataSet.Post;
      end;
    end;
  end;
end;

MartynA 回答得好。

如果您不想限制导航器组件并且通常有这样的检查,您可以像这样覆盖 TFDQuery.InternalPost:

procedure TFDQuery.InternalPost;
begin
  if State in [dsEdit, dsInsert] then
  begin
    if MessageDlg('Save changes?', mtWarning, [mbYes, mbNo], 0) = mrNo then
      Cancel();
  end;

  inherited;
end;