http://3y.uu456.com/bp_0let602ecq83uyx977cu_1.html

TClientDataSet天生具有缓冲更新功能。

为了使数据更新回数据存储源,我们要调用TClientDataSet中对应的方法。如果ClientDataSet与

DataSetProvider关联,那么仅需调用TClientDataSet的ApplyUpdates方法即可保存数据的更新,但如果 TClientDataSet没有对应的TDataSetProvider存在,而是直接同文件关联,那么,这种方式是非常有趣的,我们在 BriefCase模型中会再次讲解这个问题。此时,如果使用TClientDataSet的SaveToFile和LoadFromFile,都会保留 着Delta。调用MergeChangeLog和ClearChanges后,Delta的内容才会被

清空。只是前者是将Delta的数据 同Data结合起来,将改变存储到物理介质上,而ClearChanges则是一股脑儿全部清空,将数据回复到原始状态。大部分的应用都是将 TClientDataSet与TDataSetProvider结合使用的。两者联合使用的行为反映了Borland的设计宗旨,就是要提供一个面向分 布式环境的思路。我们下面来慢慢解释。

当我们将TClientDataSet对象的Active属性设为True或者调用其Open方法后,ClientDataSet会向

DataSetProvider发送一个取数据包请求。于是DataSetProvider便会打开对应的数据集,将记录指针指向第一条记录,然后从头到 尾依次扫描。对于扫描到的每一条记录,都会将其编码成一个variant数组,我们通常将它称之为数据包。完成扫描后,DataSetProvider会 关闭指向的数据集,并将所有的这些数据包传递给

ClientDataSet。在我提供的演示程序中,你可以清楚地看到这种行为(毕竟眼见为实吗!)。程序 主界面右边的DBGrid连接到一个指向数据库表的数据源,DataSetProvider即指向此表。当选择了ClientDataSet | Load菜单项时,你可以看到表格的数据被依次扫描,一旦到达最后一条记录,表格便会被关闭,右边的DBGrid被清空,而左边反映 ClientDataSet数据的DBGrid便出显示出内存中的数据来。由于这个过程会在DBGrid上反映出来,所以不到1000条记录的取出时间 中,大部分都浪费在屏幕的更新显示上了,你可以选择ClientDataSet | View Table Loading来禁止显示,而达到加速的目的。

在上面的描述中,我们没有提到一个重要的环节,即数据包是如何还原成表格的。那是因为DataSetProvider会将数据包中的元数据解码出 来,根据元数据(我们可以理解为数据表的结构)便可以构造出与物理数据表一模一样的内存虚拟表。但要注意的是,尽管DataSetProvider指向的 数据表可能有多个索引,但这些信息是不会放在数据包中的,换句话说,ClientDataSet当中的数据默认情况下是无索引的。但因为 ClientDataSet具有与TDataSet一致的行为,所以我们可以在此基础上根据需要重建索引。

在ClientDataSet中的数据被修改后,可以提交给物理数据表持久化这此改变。这个工作便是由DataSetProvider完成的。内部 工作原理是:DataSetProvider创建一个TSQLResolver的实例,这个实例会生成要在底层数据上执行更改的SQL语句。详细地说,就 是对修改日志中的每一条被删除、插入、更改记录生成对应的SQL语句。这个语句的生成也可以由用户控制,DataSetProvider的 UpdateMode属性和ClientDataSet中的ProviderFlags属性都对SQL语句的生成有影响。

当然,你也可以换一种方式,即采取同单机或C/S结构一样的数据直接操作机制,绕过SQL语句和缓冲更新机制来修改数据库。只需将 ResolveToDataSet属性设为True,那么DataSetProvider在持久化更新时便不会使用TSQLResolve,而是直接修改 物理数据源。即定位到要删除的记录,调用删除语句,定位到修改记录,调用修改语句。我们可以对演示程序稍加修改,观察此种行为。请将演示程序中的 DataSetProvider的

ResolveToDataSet属性由False改为True,运行。在界面中修改数据并且保存,你将会看到右边的导 航按钮会在瞬间变得可用。