DataSnap下通过TQuery—TDataSetProvider—TClientDataSet获取数据,如果是主从数据,则每条主表记录都会触发从表数据的获取。
这种获取和组织数据的方式有一个问题:如果主表纪录有数千条,则会导致从表SQL语句运行数千次,从效率和性能上讲是不合理的。所以在很多情况下,对主从表可以考虑采用分包获取的方式,即一次性获取主表数据,但是不获取从表数据,当需要显示或编辑从表数据时,再获取该主表纪录对应的从表数据。要实现这个功能,按照帮助说明要求,需要调整TDataSetProvider和TClientDataSet的相关属性:
TDataSetProvider
Options := Options + [poFetchDetailsOnDemand];
TClientDataSet
FetchOnDemand := False;
测试程序如下图:
将从表的DataSetField设置为主表的相应字段:
cdsDetail.DataSetField := cdsMain.FieldByName(QryDetail.Name) as TDataSetField;
将cdsMain的FetchOnDemand 属性设置为 False后,看到:
1、在主表开启时,确实没有一次性获取每条主记录对应的从表纪录,而只是第一条主记录获取了对应的从表数据;
2、滚动主表纪录时,DataSnap自动获取了该主记录对应的从表纪录,没有起到通过代码进行分包获取的作用。
后来将cdsDetail的FetchOnDemand 属性设置为 False后,看到滚动主记录时,DataSnap没有自动获取主记录对应的从表纪录。看来还是没有理解到位,FetchOnDemand 属性的设置是针对从表数据集的,而不是针对主表数据集。
经过多次尝试,得出以下结论:
想要实现主从表分包获取数据,除服务器上将TDataSetProvider的Options中加入poFetchDetailsOnDemand,客户端可以采用以下模式:
1、将从表的FetchOnDemand 属性设置为 False,然后通过代码
cdsMain.FetchDetails;
以主表的形式获取从表数据。
2、保持从表的FetchOnDemand 属性为 True,在开启主表时,不设置从表的DataSetField属性,当需要获取从表数据时,再设置DataSetField属性可以自动获取从表数据。处理完成后将从表的DataSetField属性设置为nil,可以关闭从表数据的自动获取。当然也可以将从表的FetchOnDemand 属性为 False,采用代码方式获取。