Delphi三層開發小技巧:TClientDataSet的Delta妙用

hrdzkj發表於2013-07-02

Delphi三層開發小技巧:TClientDataSet的Delta妙用

from :
http://www.cnblogs.com/fyen/archive/2011/04/21/2023223.html

 

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.程式碼如下:

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

const sql='select * from %s where 1<>1';

var sqlstr:string;

      ErrCount:Integer;

begin

    Result:=False;

   sqlstr:=Format(sql,[UpdateTable]);

   try

       Conn.BeginTrans;

       Query.Close;

       Query.sql.text:=sqlstr;

       Query.open;

      Provider.ApplyUpdates(Delta,-1,ErrCount);

      Result:=ErrCount=0;

      if Result then

         Conn.CommitTrans

      else Conn.RollbackTrans;

   except

       on E:Exception do

       begin

           Conn.RollbackTrans;

          err:=E.Message;

       end;

   end;

end;

    到此,通用的更新方法已經完成了.不過客戶端的ClientDataSet還不能查詢顯示資料,因此,還要寫一個查詢方法:

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

    引數sqlstr就是要持行的查詢語句,Data返回查詢結果,錯誤時err返回錯誤訊息

   QuerySQL實現程式碼如下:

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

begin

    Result:=False;

   try

      Query.close;

      Query.sql.text:=sqlstr;

        Query.sql.Open;

        Data:=Provider.Data;

       Result:=True;

    Except

         on E:Exception do

             err:=E.Message;

    end;

end;

    到這裡,中間層的程式碼已經完了,客戶端的呼叫就簡單了.比如客戶端有個資料模組DM,上面放一個DcomConnection或者SocketConnection,名叫Conn.例如,我們現在要做一個商品管理的功能,在窗體上放一個TClientDataSet叫Cds,放DataSource,DBGrid等,設定好相應的屬性.然後在窗體建立(Create事件)時查詢回所有資料,程式碼如下:

const sql='select * from xxxx';

var Data:Variant;

      err:String;

begin

   if Dm.Conn.AppServer.QuerySQL(sql,Data,err) then

      Cds.Data:=Data

   else MessageBox(self.handle,pchar('查詢資料出錯:'+err),'錯誤',MB_OK+MB_ICONERROR);      

end;

   然後還有"新增","修改","刪除"按扭,程式碼都和我們平時操作一樣,比如"新增"按扭的程式碼:

   cds.append;

   cds.fieldbyname('xxx').asinteger:=xxx;

   //....

   cds.post;

    修改,刪除也這樣寫.不過現在還有個小問題是,這個表的主鍵的生成問題,這裡我們不能用自增主鍵,要自己自己生成主鍵,這樣你還得在中間層寫一箇中間層生成主鍵的方法,在"增加"按扭時生呼叫生成主鍵,然後再上面的操作.這裡不再多說.

    增刪改完後,這時的資料還在客戶端的記憶體裡,想儲存到遠端的中間層伺服器就要用到我們剛才的方法了,下面就是"儲存"按扭下的程式碼:

var err:string;

begin

    if cds.ChangeCount=0 then exit;//資料沒改變就不用提交了

    if Dm.Conn.AppServer.ApplyUpdates('xxx',cds.Delta,err) then//xxx就是表名了

    begin

       MessageBox(self.handle,'儲存成功!','提示',MB_OK+MB_ICONINFORMATION);

        cds.MergeChangeLog;//合併所有改變的資料

    end else MessageBox(self.handle,pchar('儲存出錯:'+err),'錯誤',MB_OK+MB_ICONERROR);

end;

   到此,這篇文章也講完了.用這個方法,那些單表的基礎資料更新還可以寫成一個祖先類,只要加一個取得更新表名的虛方法,比如:function TableName:string;virtual;然後其後代只要override這個方法,返回各自的表名,其他的一句程式碼都不用寫.

 

相關文章