使用 poFetchDetailsOnDemand 刷新嵌套数据集 [英] Refresh Nested DataSet with poFetchDetailsOnDemand

查看:18
本文介绍了使用 poFetchDetailsOnDemand 刷新嵌套数据集的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有办法只刷新详细数据集而不重新加载所有主数据集?

Is there a way to refresh only the Detail DataSet without reloading all master dataset?

这是我迄今为止尝试过的:

this is what I've tried so far:

DM.ClientDataSet2.Refresh;      
DM.ClientDataSet2.RefreshRecord;

我也试过了:

DM.ClientDataSet1.Refresh;

但是上面的方法刷新的是整个Master数据集,而不仅仅是当前记录.

But the method above refreshes the entire Master dataset, not just the current record.

现在,下面的代码似乎可以做任何事情:

Now, the following code seems to do anything:

DM.ClientDataSet1.RefreshRecord;

是否有解决方法或正确的方法来做我想做的事?(也许是插入器...)

Is there a workaround or a proper way to do what I want? (maybe an interposer...)

附加信息:

ClientDataSet1 = 主数据集

ClientDataSet2 = 详细数据集,如下:*

object ClientDataSet2: TClientDataSet
    Aggregates = <>
    DataSetField = ClientDataSet1ADOQuery2
    FetchOnDemand = False
    .....
end

提供者属性:

object DataSetProvider1: TDataSetProvider
    DataSet = ADOQuery1
    Options = [poFetchDetailsOnDemand]
    UpdateMode = upWhereKeyOnly
    Left = 24
    Top = 104
  end

推荐答案

谷歌搜索发现许多文章说,如果不关闭并重新打开主 CDS,OP 不会关闭并重新打开主 CDS,则根本不可能使用嵌套的 ClientDataSets想在这种情况下做.不过……

Googling finds numerous articles that say that it isn't possible at all with nested ClientDataSets without closing and re-opening the master CDS, which the OP doesn't want to do in this case. However ...

对 q 的简短回答是肯定的,在我测试过的相当简单的情况下,它非常简单,虽然有点啰嗦;正确采取必要的步骤需要一段时间才能弄清楚.

The short answer to the q is yes, in the reasonably simple case I've tested, and it's quite straightforward, if a bit long-winded; getting the necessary steps right took a while to figure out.

代码如下,其中包含解释其工作原理和一些潜在问题以及如何避免或解决这些问题的注释.我只用 TAdoQueries 为 CDS 的 Provider 进行了测试.

The code is below and includes comments explaining how it works and a few potential problems and how it avoids or works around them. I have only tested it with TAdoQueries feeding the CDSs' Provider.

当我开始研究这一切时,很快就发现,与通常的主人+ 详细信息设置,尽管 Providers + CDS 很乐意从服务器刷新主数据,但他们根本不会刷新 detail 记录,一旦它们从服务器第一次被读取cdsMaster 已打开.当然,这可能是设计使然.

When I started looking into all this, it soon became apparent that with the usual master + detail set-up, although Providers + CDSs are happy to refresh the master data from the server, they simply will not refresh the detail records once they've been read from the server for the first time since the cdsMaster was opened. This may be by design of course.

我认为我不需要发布 DFM 来使用代码.我只是以通常的主从方式设置了 AdoQueries(详细查询以主服务器的 PK 作为参数),一个 DataSetProvider 指向主 AdoQuery,一个主 CDS 指向提供程序,一个详细 cDS 指向cdsMaster 的 DataSetField.为了试验并了解发生了什么,每个数据集都有 DBGrids 和 DBNavigators.

I don't think I need to post a DFM to go with the code. I simply have AdoQueries set up in the usual master-detail way (with the detail query having the master's PK as a parameter), a DataSetProvider pointed at the master AdoQuery, a master CDS pointed at the provider, and a detail cDS pointed at the DataSetField of the cdsMaster. To experiment and see what's going on, there are DBGrids and DBNavigators for each of these datasets.

简而言之,以下代码的工作方式是将 AdoQuery master 和 CDS masterdown 临时过滤到当前行,然后强制刷新它们的数据和当前 master 行的 dtail 数据.这样做,与我尝试过的任何其他方式不同,会导致嵌套在 cdsMaster 的 DataSet 字段中的详细信息行被刷新.

In brief, the way the code below works is to temporarily filter the AdoQuery master and the CDS masterdown to the current row and then force a refresh of their data and the dtail data for the current master row. Doing it this way, unlike any other I tried, results in the detail rows nested in the cdsMaster's DataSet field getting refreshed.

顺便说一句,我尝试过的其他死胡同包括和不设置 poFetchDetailsOnDemand 为 true,同上 cdsMaster.FetchDetailsOnDemand.显然FetchDetailsOnDemand"并不意味着 ReFetchDetailsOnDemand!

Btw, the other blind alleys I tried included with and without poFetchDetailsOnDemand set to true, ditto cdsMaster.FetchDetailsOnDemand. Evidently "FetchDetailsOnDemand" doesn't mean ReFetchDetailsOnDemand!

我遇到了一个或两个问题,让我的解决方案"发挥作用,这个 SO 问题中描述了最棘手的问题:刷新嵌套在 DataSetField 中的 ClientDataSet

I ran into a problem or two getting my "solution" working, the stickiest one being described in this SO question: Refreshing a ClientDataSet nested in a DataSetField

我已经验证这可以与 Sql Server 2000(!) 后端一起正常工作,包括从 ISqlW 获取在服务器上触发的行数据更改.我还使用 Sql Server 的 Profiler 验证了刷新中的网络流量仅涉及单个主行及其详细信息.

I've verified that this works correctly with a Sql Server 2000(!) back-end, including picking up row data changes fired at the server from ISqlW. I've also verified, using Sql Server's Profiler, that the network traffic in a refresh only involves the single master row and its details.

Delphi 7 + Win7 64 位,顺便说一句.

Delphi 7 + Win7 64-bit, btw.

procedure TForm1.cdsMasterRowRefresh(MasterPK : Integer);
begin
  //  The following operations will cause the cursor on the cdsMaster to scroll
  //  so we need to check and set a flag to avoid re-entrancy
  if DoingRefresh then Exit;
  DoingRefresh := True;

  try
    //  Filter the cdsMaster down to the single row which is to be refreshed.
    cdsMaster.Filter := MasterPKName + ' = ' + IntToStr(MasterPK);
    cdsMaster.Filtered := True;
    cdsMaster.Refresh;
    Inc(cdsMasterRefreshes);  //  just a counter to assist debugging

    //  release the filter
    cdsMaster.Filtered := False;

    // clearing the filter may cause the cdsMaster cursor to move, so ...
    cdsMaster.Locate(MasterPKName, MasterPK, []);
  finally
    DoingRefresh := False;
  end;
end;

procedure TForm1.qMasterRowRefresh(MasterPK : Integer);
begin
  try
    //  First, filter the AdoQuery master down to the cdsMaster current row
    qMaster.Filter := MasterPKName + ' = ' + IntToStr(MasterPK);
    qMaster.Filtered := True;

    //  At this point Ado is happy to refresh only the current master row from the server
    qMaster.Refresh;

    // NOTE:
    //  The reason for the following operations on the qDetail AdoQuery is that I noticed
    //  during testing situations where this dataset would not be up-to-date at this point
    //  in the refreshing operations, so we update it manually.  The reason I do it manually
    //  is that simply calling qDetail's Refresh provoked the Ado "Insufficient key column
    //  information for updating or refreshing" despite its query not involving a join
    //  and the underlying table having a PK

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

    //  With the master and detail rows now re-read from the server, we can update
    //  the cdsMaster
    cdsMasterRowRefresh(MasterPK);
  finally
    //  Now, we can clear the filter
    qMaster.Filtered := False;
    qMaster.Locate(MasterPKName, MasterPK, []);
    // Obviously, if qMaster were filtered in the first place, we'd need to reinstate that later on
  end;
end;

procedure TForm1.RefreshcdsMasterAndDetails;
var
  MasterPK : Integer;
begin
  if cdsMaster.ChangeCount > 0 then
    raise Exception.Create(Format('cdsMaster has %d change(s) pending.', [cdsMaster.ChangeCount]));
  MasterPK := cdsMaster.FieldByName(MasterPKName).AsInteger;

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

  try
    try
      qMasterRowRefresh(MasterPK);
    except
      //  Add exception handling here according to taste
      //  I haven't encountered any during debugging/testing so:
      raise;
    end;
  finally
    qMaster.EnableControls;
    qDetail.EnableControls;
    cdsMaster.EnableControls;
    cdsDetail.EnableControls;
  end;
end;

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

procedure TForm1.cdsMasterAfterPost(DataSet: TDataSet);
//  NOTE:  The reason that this, in addition to cdsMasterAfterScroll, calls RefreshcdsMasterAndDetails is
//         because RefreshcdsMasterAndDetails only refreshes the master + detail AdoQueries for the current
//         cdsMaster row.  Therefore in the case where the current cdsMaster row or its detail(s)
//         have been updated, this row needs the refresh treatment before we leave it.
begin
  cdsMaster.ApplyUpdates(-1);
  RefreshcdsMasterAndDetails;
end;

procedure TForm1.btnRefreshClick(Sender: TObject);
begin
  RefreshcdsMasterAndDetails;
end;

procedure TForm1.cdsDetailAfterPost(DataSet: TDataSet);
begin
  cdsMaster.ApplyUpdates(-1);
end;

这篇关于使用 poFetchDetailsOnDemand 刷新嵌套数据集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆