分享

Delphi三层开发小技巧:TClientDataSet的Delta妙用

 aaie_ 2011-11-23
Delphi做三层开发时,很多人都会在客户端放一个TClientDataSet,中间层远程数据模块就对应放一个TDataSetProvider, 然后再连起来.其实这种方法很烦琐,而且程序痈肿不甘,不好维护.我们都知道TClientDataSet的Delta属性记录了数据的所有修改,应用它我们就可以方便的实现一个单表更新的通用方法.

   首先,在中间层添加一个方法,就叫ApplyUpdates吧.方法定义如下:

   function ApplyUpdates(const UpdateTable:String;Delta:Variant;out err:String):Boolean;

参数UpdateTable是指要更新的表名,Delta是指传过来的TClientDataSet的Delta属性,如果更新错误err返回错误的内容.下面实现这个方法,首先在DataModule上放一个Query,Query连上Connection,然后再放一个 TDataSetProvider连Query.代码如下:

01 function TRoDm.ApplyUpdates(const UpdateTable:String;Delta:Variant;out err:String):Boolean;
02   
03 const sql='select * from %s where 1<>1';
04   
05 var sqlstr:string;
06   
07       ErrCount:Integer;
08   
09 begin
10   
11     Result:=False;
12   
13    sqlstr:=Format(sql,[UpdateTable]);
14   
15    try
16   
17        Conn.BeginTrans;
18   
19        Query.Close;
20   
21        Query.sql.text:=sqlstr;
22   
23        Query.open;
24   
25       Provider.ApplyUpdates(Delta,-1,ErrCount);
26   
27       Result:=ErrCount=0;
28   
29       if Result then
30   
31          Conn.CommitTrans
32   
33       else Conn.RollbackTrans;
34   
35    except
36   
37        on E:Exception do
38   
39        begin
40   
41            Conn.RollbackTrans;
42   
43           err:=E.Message;
44   
45        end;
46   
47    end;
48   
49 end;

    到此,通用的更新方法已经完成了.不过客户端的ClientDataSet还不能查询显示数据,因此,还要写一个查询方法:

    function QuerySQL(const sqlstr:string;out Data:Variant;out err:String):Boolean;

    参数sqlstr就是要持行的查询语句,Data返回查询结果,错误时err返回错误消息

   QuerySQL实现代码如下:

01 function TRoDm.QuerySQL(const sqlstr:string;out Data:Variant;out err:String):Boolean;
02   
03 begin
04   
05     Result:=False;
06   
07    try
08   
09       Query.close;
10   
11       Query.sql.text:=sqlstr;
12   
13         Query.sql.Open;
14   
15         Data:=Provider.Data;
16   
17        Result:=True;
18   
19     Except
20   
21          on E:Exception do
22   
23              err:=E.Message;
24   
25     end;
26   
27 end;

    到这里,中间层的代码已经完了,客户端的调用就简单了.比如客户端有个数据模块DM,上面放一个DcomConnection或者 SocketConnection,名叫Conn.例如,我们现在要做一个商品管理的功能,在窗体上放一个TClientDataSet叫Cds,放 DataSource,DBGrid等,设置好相应的属性.然后在窗体创建(Create事件)时查询回所有数据,代码如下:

01 const sql='select * from xxxx';
02   
03 var Data:Variant;
04   
05       err:String;
06   
07 begin
08   
09    if Dm.Conn.AppServer.QuerySQL(sql,Data,err) then
10   
11       Cds.Data:=Data
12   
13    else MessageBox(self.handle,pchar('查询数据出错:'+err),'错误',MB_OK+MB_ICONERROR);      
14   
15 end;
16   
17    然后还有"添加","修改","删除"按扭,代码都和我们平时操作一样,比如"添加"按扭的代码:
18   
19    cds.append;
20   
21    cds.fieldbyname('xxx').asinteger:=xxx;
22   
23    //....
24   
25    cds.post;

    修改,删除也这样写.不过现在还有个小问题是,这个表的主键的生成问题,这里我们不能用自增主键,要自己自己生成主键,这样你还得在中间层写一个中间层生成主键的方法,在"增加"按扭时生调用生成主键,然后再上面的操作.这里不再多说.

    增删改完后,这时的数据还在客户端的内存里,想保存到远程的中间层服务器就要用到我们刚才的方法了,下面就是"保存"按扭下的代码:

01 var err:string;
02   
03 begin
04   
05     if cds.ChangeCount=0 then exit;//数据没改变就不用提交了
06   
07     if Dm.Conn.AppServer.ApplyUpdates('xxx',cds.Delta,err) then//xxx就是表名了
08   
09     begin
10   
11        MessageBox(self.handle,'保存成功!','提示',MB_OK+MB_ICONINFORMATION);
12   
13         cds.MergeChangeLog;//合并所有改变的数据
14   
15     end else MessageBox(self.handle,pchar('保存出错:'+err),'错误',MB_OK+MB_ICONERROR);
16   
17 end;

   到此,这篇文章也讲完了.用这个方法,那些单表的基础数据更新还可以写成一个祖先类,只要加一个取得更新表名的虚方法,比如:function TableName:string;virtual;然后其后代只要override这个方法,返回各自的表名,其他的一句代码都不用写.

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多