刷新嵌套在DataSetField中的ClientDataSet

时间:2014-07-10 20:28:00

标签: delphi ado master-detail tclientdataset

我几乎已经完成了一些代码来解决去年这个未得到答复的q中的问题:

Refresh Nested DataSet with poFetchDetailsOnDemand

接受的智慧是,如果不关闭并重新打开主CDS,就无法从服务器刷新嵌套的详细CDS,但显然这会产生不成比例的网络流量,只需刷新单个主行及其详细行。

我想到了一种刷新细节CDS的简单方法 从服务器和几乎工作。我的代码基本上暂时刷新细节 将过滤器应用于主ADO查询以将其过滤到当前主行,并且当该过滤器生效时, 通过对其应用类似的过滤器然后调用其Refresh方法来刷新主CDS。这是由主CDS AfterScroll事件触发的。

只有一个 teeny 问题:在我的表单上,以及4个数据集和附带的网格,我在表单上有一个刷新按钮,调用我的RefreshcdsMasterAndDetails' s 也在cdsMasterAfterScroll中调用。如果我使用其网格移动主CDS,我的代码一切正常,并且详细CDS行正确更新,以及AdoQuery详细信息中的那些<>但如果我通过单击Refresh按钮触发它,则CDS详细信息行仅在每次单击“刷新”按钮时更新。

我的问题是:为什么我的代码在点击按钮而不是AfterScroll事件时触发的效果会有所不同,因为它可靠地完成它的功能。应该从AfterScroll事件中调用,但只能在按下按钮时触发每隔一次?

//Obviously MasterPKName below is a const and DoingRefresh is a boolean
// flag on the form

procedure TForm1.cdsMasterRowRefresh(MasterPK : Integer);
begin
  if DoingRefresh then Exit;

  DoingRefresh := True;

  try
    cdsMaster.Prior;
    cdsMaster.Next;
    cdsMaster.Filter := MasterPKName + ' = ' + IntToStr(MasterPK);
    cdsMaster.Filtered := True;
    cdsMaster.Refresh;
    cdsMaster.Filtered := False;

    cdsMaster.Locate(MasterPKName, MasterPK, []);

  finally
    DoingRefresh := False;
  end;
end;

procedure TForm1.qMasterRowRefresh(MasterPK : Integer);
begin
  qMaster.Filter := MasterPKName + ' = ' + IntToStr(MasterPK);
  qMaster.Filtered := True;
  qMaster.Refresh;

  cdsMasterRowRefresh(MasterPK);

  qMaster.Filtered := False;
  qMaster.Locate(MasterPKName, MasterPK, []);
end;

procedure TForm1.RefreshcdsMasterAndDetails;
var
  MasterPK : Integer;
begin
  MasterPK := cdsMaster.FieldByName(MasterPKName).AsInteger;

  cdsDetail.DisableControls;
  cdsMaster.DisableControls;
  qDetail.DisableControls;
  qMaster.DisableControls;

  try
    qMasterRowRefresh(MasterPK);
  finally
    qMaster.EnableControls;
    qDetail.EnableControls;
    cdsMaster.EnableControls;
    cdsDetail.EnableControls;
  end;
end;

procedure TForm1.cdsMasterAfterScroll(DataSet: TDataSet);
begin
  RefreshcdsMasterAndDetails;
end;

1 个答案:

答案 0 :(得分:1)

尽管经过了大量的仔细观察和调试,我仍然无法解释为什么我的CDS刷新代码 如果在主CDS的AfterScroll事件中调用,则表现不同 detail CDS总是正确更新,并在ButtonClick处理程序中 详细信息CDS仅在每次单击时更新。我想这是件好事 与主CDS光标已经移动的事实有关 调用AfterScroll处理程序,与我单击按钮的情况不同。

但是,我找到了一个简单的解决方法和修复方法。

解决方法就是不要在之前调用4个数据集上的DisableControls 做刷新。然后,细节CDS始终正确刷新。任何其他 禁用部分或全部数据集的排列会导致我的q差异。我不喜欢这种解决办法,因为cdsMaster DBGrid必须一直滚动数据,只需刷新一个主行+其详细信息。

解决方法是做一些反思我应该首先做的事情,即强迫 刷新详细的ADO查询(使用我的数据,只需调用它的Refresh,这是我的第一次尝试 在修复时,会引发熟悉的Ado错误" Insuffient键列信息 更新......"尽管详细信息表在服务器上有PK。)

所以,这是修复:

procedure TForm1.qMasterRowRefresh(MasterPK : Integer);
begin
  try
    qMaster.Filter := MasterPKName + ' = ' + IntToStr(MasterPK);
    qMaster.Filtered := True;

    qMaster.Refresh;

    //  Do NOT omit the next 3 lines, needed to ensure that the detail query
    //  and hence the detail CDS, is refreshed

    qDetail.Parameters.ParamByName(MasterPKName).Value := MasterPK;
    qDetail.Close;
    qDetail.Open;

    cdsMasterRowRefresh(MasterPK);

  finally
    qMaster.Filtered := False;
    qMaster.Locate(MasterPKName, MasterPK, []);
  end;
end;

当我通过研究一个早期未解答的SO问题进入这个问题时,我会 将代码的更新版本移植到该代码的答案。