浏览结果时 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
调用的,而不是由于用户单击保存按钮。
解决此问题的简单方法是捕获 DBNavigator
的 BeforeAction
事件,然后它会在数据集上调用导航操作,这将触发 .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;
我有一个 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
调用的,而不是由于用户单击保存按钮。
解决此问题的简单方法是捕获 DBNavigator
的 BeforeAction
事件,然后它会在数据集上调用导航操作,这将触发 .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;