bestlong 怕失憶論壇

 

 

搜索
bestlong 怕失憶論壇 論壇 Delphi 更新多個資料表的方法
查看: 4792|回復: 0
go

更新多個資料表的方法 [複製鏈接]

Rank: 9Rank: 9Rank: 9

1#
發表於 2007-3-7 10:22 |只看該作者 |倒序瀏覽 |打印
問題描述

使用 Delphi5 + BDE + MIDAS

我希望能一次更新兩個以上的資料表,可是這些異動必須在同一個交易中,也就是其中任何一個資料表發生錯誤時必須全部rollback,應該怎麼做?

典型的場景

  假設有一個訂單管理程式,當新增一筆訂單時需要同時更新客戶資料與訂單資料。一般的做法是在 DataSetProvider 的 BeforeUpdateRecord 事件中加入更新其他資料表的程式碼,例如:
  
  1. procedure TForm1.dspOrdersBeforeUpdateRecord(Sender: TObject; SourceDS: TDataSet; DeltaDS: TClientDataSet; UpdateKind: TUpdateKind; var Applied: Boolean);
  2. begin
  3.   if UpdateKind = ukModify then
  4.   begin
  5.     qryUpdate.SQL.Text := 'update Customer set City="AAA" where CustNo="1221"';
  6.     qryUpdate.ExecSQL;
  7.   end;
  8. end;
複製代碼

  
  以上面的例子來看,會先更新客戶資料 Customer,然後再更新訂單資
  料 Orders。可是如果更新 Orders 時發生了錯誤,之前對於 Customer
  所做的異動卻無法 rollback 了。即使這兩個資料集元件都連結到相同
  的 TDatabase 元件也一樣。這樣一來仍然無法達到資料完整性。

解決方案 A:

  使用 Dan Miser 的 MIDAS Essensial Pack。使用時需 uses CDSUtil
  單元,程式碼可以參考下面的範例:

    App server 端:

  1. procedure TMtsDmod.MyApplyUpdates(var vDeltaArray: OleVariant; vProviderArray: OleVariant);
  2. begin
  3.   try
  4.     CDSApplyUpdates(vDeltaArray, vProviderArray);
  5.     SetComplete;
  6.   except
  7.     SetAbort;
  8.   end;
  9. end;
複製代碼


    Client 端:

  1. procedure TForm1.btnApplyUpdatesClick(Sender: TObject);
  2. var
  3.   cdsArray: array [0..1] of TCLientDataSet;
  4.   vDeltaArray: OleVariant;
  5.   vProviderArray: OleVariant;
  6. begin
  7.   cdsArray[0] := cdsPubs;     // Master
  8.   cdsArray[1] := cdsTitles;   // Detail
  9.   vDeltaArray := RetrieveDeltas(cdsArray);
  10.   vProviderArray := RetrieveProviders(cdsArray);
  11.   DCOMConnection1.AppServer.ApplyUpdates(vDeltaArray, vProviderArray);
  12.   ReconcileDeltas(cdsArray, vDeltaArray);
  13. end;
複製代碼



解決方案 B:
  
  不要讓 DataSetProvider 更新資料,讓其連接的資料集元件自行更新資料。首先, DataSetProvider 的 ResolveToDataSet 必須設為 True 。然後在 qryOrders 的 OnUpdateRecord 事件中撰寫更新其他資料表的程式碼,像這樣:
  
  1. procedure TForm1.qryOrdersUpdateRecord(DataSet: TDataSet; UpdateKind: TUpdateKind; var UpdateAction: TUpdateAction);
  2. begin
  3.   if UpdateKind = ukModify then
  4.   begin
  5.     qryUpdate.SQL.Text := 'update Customer set City="AAA" where CustNo="1221"';
  6.     qryUpdate.ExecSQL;
  7.   end;
  8. end;
複製代碼

  
  你可以故意讓 Orders 在更新時發生錯誤,看看 Customer 資料表中
  CustNo 為 '1221' 的那筆記錄的 City 欄位是否被改為 'AAA',如果
  不是的話就表示這個方法的確可行,你可以自行驗證看看。
   

解決方案 C:

  在 dataset provider 的 BeforeUpdateRecord 事件中自行處理掉所有
  的更新的工作。例如:

  1. procedure TForm1.dspOrdersBeforeUpdateRecord(Sender: TObject; SourceDS: TDataSet; DeltaDS: TClientDataSet; UpdateKind: TUpdateKind; var Applied: Boolean);
  2. begin
  3.   qryCustomer.UpdateObject := usqlCustomer;
  4.   usqlCustomer.SetParams(UpdateKind);
  5.   usqlCustomer.ExecSQL(UpdateKind);

  6.   qryOrders.UpdateObject := usqlOrders;
  7.   usqlOrders.SetParams(UpdateKind);
  8.   usqlOrders.ExecSQL(UpdateKind);

  9.   Applied := True;
  10. end;
複製代碼


使用這個方法時別忘了最後要將 Applied 設為 True, 告訴 dataset provider 你已經完成更新資料的工作。
我是雪龍
http://blog.bestlong.idv.tw
http://www.bestlong.idv.tw
‹ 上一主題|下一主題

Archiver|怕失憶論壇

GMT+8, 2024-4-26 19:36 , Processed in 0.013562 second(s), 10 queries .

Powered by Discuz! X1.5

© 2001-2010 Comsenz Inc.