谷歌搜索可以找到很多文章,称在嵌套的ClientDataSets中不关闭和重新打开主CDS是不可能的,而这正是本文作者不想要做的。然而……
简短地回答问题,是的,在我测试过的相当简单的情况下,它是可行的,而且非常简单,尽管有点冗长;弄清楚必要的步骤花了一些时间。下面的代码包括解释它如何工作以及一些潜在问题以及如何避免或解决它们的注释。我只用TAdoQueries测试过提供CDSs的情况。
当我开始研究所有这些时,很快就明显了,虽然提供程序和CDS可以从服务器刷新主数据,但自从cdsMaster被打开以来,它们根本不会刷新细节记录。这可能当然是设计上的。
我认为我不需要发布DFM与代码一起。 我只是按照通常的主从方式设置了AdoQueries(详细查询具有主键作为参数),将DataSetProvider指向主AdoQuery,将主CDS指向提供程序,并将详细cDS指向cdsMaster的DataSetField。 为了实验和查看正在进行的操作,每个数据集都有DBGrid和DBNavigator。
简而言之,下面的代码的工作方式是临时过滤AdoQuery主和CDS masterdown到当前行,然后强制刷新它们的数据以及当前主行的dtail数据。 以这种方式执行,与我尝试过的任何其他方式不同,结果是在cdsMaster的DataSet字段中嵌套的详细行得到刷新。
顺便说一句,我尝试的其他死胡同包括使用和不使用poFetchDetailsOnDemand以及cdsMaster.FetchDetailsOnDemand。 显然,“FetchDetailsOnDemand”并不意味着“ReFetchDetailsOnDemand”!
我遇到了一些问题,让我的“解决方案”工作起来有点困难,其中最棘手的一个在这个SO问题中描述:
刷新嵌套在DataSetField中的ClientDataSet
我已经验证了它可以与Sql Server 2000(!)后端正确地工作,包括从ISqlW触发的服务器行数据更改。我还使用Sql Server的Profiler验证了,在刷新时网络流量只涉及单个主行及其详情。
顺便说一下,使用的是Delphi 7 + Win7 64位操作系统。
procedure TForm1.cdsMasterRowRefresh(MasterPK : Integer);
begin
if DoingRefresh then Exit;
DoingRefresh := True;
try
cdsMaster.Filter := MasterPKName + ' = ' + IntToStr(MasterPK);
cdsMaster.Filtered := True;
cdsMaster.Refresh;
Inc(cdsMasterRefreshes);
cdsMaster.Filtered := False;
cdsMaster.Locate(MasterPKName, MasterPK, []);
finally
DoingRefresh := False;
end;
end;
procedure TForm1.qMasterRowRefresh(MasterPK : Integer);
begin
try
qMaster.Filter := MasterPKName + ' = ' + IntToStr(MasterPK);
qMaster.Filtered := True;
qMaster.Refresh;
qDetail.Parameters.ParamByName(MasterPKName).Value := MasterPK;
qDetail.Close;
qDetail.Open;
cdsMasterRowRefresh(MasterPK);
finally
qMaster.Filtered := False;
qMaster.Locate(MasterPKName, MasterPK, []);
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
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);
begin
cdsMaster.ApplyUpdates(-1);
RefreshcdsMasterAndDetails;
end;
procedure TForm1.btnRefreshClick(Sender: TObject);
begin
RefreshcdsMasterAndDetails;
end;
procedure TForm1.cdsDetailAfterPost(DataSet: TDataSet);
begin
cdsMaster.ApplyUpdates(-1);
end;