非原创 摘自:http://hi.baidu.com/yagzh2000/blog/item/fc69df2cb9845de78b139946.html
三层中主从表的操作(删除、新增、修改)一定要在一个事物中完成,那在Delphi中的事物又如何控制呢?我们在开发客户端时,如果为了在一个事物中而用TSqlConnection的事物来控制是徒劳的,没有一点意义,因为真正事物控制是在服务端的TDataSetProvider中产生的,它是自动产生事物的,如果有错误产生,它会回滚事物。
当客户端的ClientdataSet把Delta数据提交给远程的DataSetProvider时,这个DataSetProvider会解析这个语句,并且会自动产生一个事物,所以我们不必要写事物控制,当然用函数时而不用DataSetProvider是另外一个话题。
如果我们直接在远程端设置二个TDataSetProvider,客户端也放两个对就的ClientDataSet,并把客户端的两个数据集设置成主从可以吗?
我的回答是:绝对不可以。为什么?因为你在更新数据时是在两个DataSetProvider中产生二个不同的事物,这样的话就不能保证数据更新的完整性。
Delphi为我们提供的机制是在服务端设置好主从结构,而从表数据集变为主表的一个字段,这样当客户端连接远程的TDataSetProvider时,只把客户端主表数据控件连接到DataSetProvider就可以,从表只要设置一下DataSetField为客户端主表中那个数据集字段就可以了。当保存数据时,只用客户端主表的ApplyUpdata就可以保存主从表数据(可以有多个从表)。更新时就把主从表相关改动的数据传到远程 的DataSetProvider中,些时DataSetProvider可以开启一个事物,这样就能保证数据的完整性。
以下我详细说一下开发主从表的实例:
我用的数据集是:UniDac,它和Ado基本一样用(用mssql2000 northwind 库中的orders和order detail表做实例)
一.开发服务端
1. 放上连接数据库的控件:UniConnection.和MSSQL驱动控件SQLServerUniProvider1(ADO不需要)
2. 放上主表数据集UniQuery1改为名称 是Master,设置它的sql语句为:Select * From Orders
3. 放上主表数据集对应的DataSource,更名为DSMaster,设置这个数据源是为了让从表和它关联
4. 放上从表数据集UniQuery改为名称是Detail,设置它的Sql语句为:Select * from [Order Detail] where orderid=:A(这个形参可以随意设置)
5.设置Detail的MasterSource为DSMaster。再点选Detail属性MasterFields,在弹出的对话框中把主从表的主键及子表的外键关联起来。这样就构成了主从关系结构。
6.在Master的AfterScroll事件中对Detail中的参数A赋值
procedure TForm1.MasterAfterScroll(DataSet: TDataSet);
begin
Detail.Close;
Detail.Params[0].Value:=DataSet.FieldByName('orderid').AsInteger;
Detail.Open;
end;
7.放入名为DSP的DataSetProvider控件,设置其DataSet为Master,并设置ResloveToDataSet为Ture,为Ture表示数据的处理交由和DataSetProvider的数据集来处理,可以处理多表的数据,为False表示产生的数据是由DataSetProvider的内置Sql分析器来处理 ,但不能处理多表数据。且记一定要打开。其它的属性根据需要打开。
下图为从表设置 的MaserFields属性
二,客户端设置(为了简便测试,故把服务端和客户端放在同一界面,所以不再设置ClientDataSet的RemoteServer属性)
1.放入名为Main的ClientdataSet控件。
2.设置ClientDataSet的ProviderName为服务端的DSP.
3.在Main上打开字段属性编辑器,并在编辑器中加入服务器端Master语句产生的字段
下图为Main上的字段,你会发现有一个Detail的字段,它就是从表数据集,做为一个主表的字段了
4.再加入一个名为Child的ClientDataSet控件,它就是在客户端的从表数据集控件。
5. 设置Child的DataSetField为"MainDetail",这是可选的,即它的数据是从Main数据集的Detail字段中得到的,其它的都不用设置。
如下图
6.分别放两个DataSource和DBgrid,并分别连接到Main和Child数据集和DBGrid中,这样就可以显示数据。
此时,我们就设置好了主从关系,你可以放上一些按钮Open.代码为:Main.Open.你就会发现当客户端主表开启时,从表也跟着开启
如下图
你可以更改、删除、新增了。当然你要控制一下自增主键,这个不再多说。
还有一个发现的情况是服务端数据子表的ObjectView属性,当设置Detail的ObjectView为True时,则子表的 SQL语句中不用参数,如:Select * from [Order Detail]即可,当然那个主表数据集Master的AfterScroll中的代码就不用要了,其它都不要改变,这样的话也可以和 上面一样的操作。这个属性现在还不知是什么东东,请知道的告知一下,谢谢。
Ado中没有这个属性,但SqlQuery中有ObjectView这个属性,我发现这个属性挺重要的
另就是LookUp字段,如果要让客户端选择的话,则是在客户端的Child中设置它的LookUp字段,而在服务端设置成LookUP字段,则在客户端只显示而不能选择;