【问题标题】:FireDac FDQuery commit changed DataFields when browsing through resultsFireDac FDQuery 在浏览结果时提交更改的 DataFields
【发布时间】:2015-10-24 12:46:45
【问题描述】:

我有一个绑定到 FDConnection 的 FDQuery。

我正在使用 DB Data-Aware 组件在我的表单上显示数据。

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

一切正常。

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

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

谢谢!

【问题讨论】:

  • 默认情况下,Delphi TDataSets 在将数据集光标移动到另一行之前发布对当前行的任何更改,如 .Next 或 .Prior。标准的 TDBNavigator Post 按钮仅调用 DataSet.Post 并且本身不会将更改提交到后端数据库。您是否希望在数据集滚动之前推迟提交更改或取消更改?换句话说,当用户滚动离开具有未保存/未提交更改的行时,您希望您的应用如何响应?
  • 谢谢马丁娜。当用户滚动到下一个/上一个数据时,我想丢弃未保存/未提交的更改。我只想在用户按下绿色勾号时保存它们。

标签: delphi firedac


【解决方案1】:

就像我在评论中所说,标准的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;

【讨论】:

    【解决方案2】:

    很好的答案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;
    

    【讨论】:

    • 谢谢,但正如我在回答中所说,“全面”检查的问题在于确定调用检查的上下文。我认为如果用户每次进行显式保存(例如,通过单击 DNav 的保存按钮)时,他们都会被要求确认,他们就会被激怒。无论如何,除非您采取措施避免这种情况,否则 OP 显然已经想到了自动发布的想法。
    猜你喜欢
    • 2016-01-29
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 2011-03-09
    • 2013-08-02
    • 1970-01-01
    • 1970-01-01
    • 2015-11-15
    相关资源
    最近更新 更多