Delphi做三層開發(fā)時,很多人都會在客戶端放一個TClientDataSet,中間層遠(yuǎn)程數(shù)據(jù)模塊就對應(yīng)放一個TDataSetProvider, 然后再連起來.其實這種方法很煩瑣,而且程序癰腫不甘,不好維護.我們都知道TClientDataSet的Delta屬性記錄了數(shù)據(jù)的所有修改,應(yīng)用它我們就可以方便的實現(xiàn)一個單表更新的通用方法.
首先,在中間層添加一個方法,就叫ApplyUpdates吧.方法定義如下:
function ApplyUpdates(const UpdateTable:String;Delta:Variant;out err:String):Boolean;
參數(shù)UpdateTable是指要更新的表名,Delta是指傳過來的TClientDataSet的Delta屬性,如果更新錯誤err返回錯誤的內(nèi)容.下面實現(xiàn)這個方法,首先在DataModule上放一個Query,Query連上Connection,然后再放一個 TDataSetProvider連Query.代碼如下:
01 |
function TRoDm.ApplyUpdates(const UpdateTable:String;Delta:Variant;out err:String):Boolean; |
03 |
const sql='select * from %s where 1<>1'; |
13 |
sqlstr:=Format(sql,[UpdateTable]); |
21 |
Query.sql.text:=sqlstr; |
25 |
Provider.ApplyUpdates(Delta,-1,ErrCount); |
33 |
else Conn.RollbackTrans; |
到此,通用的更新方法已經(jīng)完成了.不過客戶端的ClientDataSet還不能查詢顯示數(shù)據(jù),因此,還要寫一個查詢方法:
function QuerySQL(const sqlstr:string;out Data:Variant;out err:String):Boolean;
參數(shù)sqlstr就是要持行的查詢語句,Data返回查詢結(jié)果,錯誤時err返回錯誤消息
QuerySQL實現(xiàn)代碼如下:
01 |
function TRoDm.QuerySQL(const sqlstr:string;out Data:Variant;out err:String):Boolean; |
11 |
Query.sql.text:=sqlstr; |
到這里,中間層的代碼已經(jīng)完了,客戶端的調(diào)用就簡單了.比如客戶端有個數(shù)據(jù)模塊DM,上面放一個DcomConnection或者 SocketConnection,名叫Conn.例如,我們現(xiàn)在要做一個商品管理的功能,在窗體上放一個TClientDataSet叫Cds,放 DataSource,DBGrid等,設(shè)置好相應(yīng)的屬性.然后在窗體創(chuàng)建(Create事件)時查詢回所有數(shù)據(jù),代碼如下:
01 |
const sql='select * from xxxx'; |
09 |
if Dm.Conn.AppServer.QuerySQL(sql,Data,err) then |
13 |
else MessageBox(self.handle,pchar('查詢數(shù)據(jù)出錯:'+err),'錯誤',MB_OK+MB_ICONERROR); |
17 |
然后還有"添加","修改","刪除"按扭,代碼都和我們平時操作一樣,比如"添加"按扭的代碼: |
21 |
cds.fieldbyname('xxx').asinteger:=xxx; |
修改,刪除也這樣寫.不過現(xiàn)在還有個小問題是,這個表的主鍵的生成問題,這里我們不能用自增主鍵,要自己自己生成主鍵,這樣你還得在中間層寫一個中間層生成主鍵的方法,在"增加"按扭時生調(diào)用生成主鍵,然后再上面的操作.這里不再多說.
增刪改完后,這時的數(shù)據(jù)還在客戶端的內(nèi)存里,想保存到遠(yuǎn)程的中間層服務(wù)器就要用到我們剛才的方法了,下面就是"保存"按扭下的代碼:
05 |
if cds.ChangeCount=0 then exit; |
07 |
if Dm.Conn.AppServer.ApplyUpdates('xxx',cds.Delta,err) then |
11 |
MessageBox(self.handle,'保存成功!','提示',MB_OK+MB_ICONINFORMATION); |
15 |
end else MessageBox(self.handle,pchar('保存出錯:'+err),'錯誤',MB_OK+MB_ICONERROR); |
到此,這篇文章也講完了.用這個方法,那些單表的基礎(chǔ)數(shù)據(jù)更新還可以寫成一個祖先類,只要加一個取得更新表名的虛方法,比如:function TableName:string;virtual;然后其后代只要override這個方法,返回各自的表名,其他的一句代碼都不用寫.