bestlong 怕失憶論壇
標題:
更新多個資料表的方法
[打印本頁]
作者:
bestlong
時間:
2007-3-7 10:22
標題:
更新多個資料表的方法
問題描述
使用 Delphi5 + BDE + MIDAS
我希望能一次更新兩個以上的資料表,可是這些異動必須在同一個交易中,也就是其中任何一個資料表發生錯誤時必須全部rollback,應該怎麼做?
典型的場景
假設有一個訂單管理程式,當新增一筆訂單時需要同時更新客戶資料與訂單資料。一般的做法是在 DataSetProvider 的 BeforeUpdateRecord 事件中加入更新其他資料表的程式碼,例如:
procedure TForm1.dspOrdersBeforeUpdateRecord(Sender: TObject; SourceDS: TDataSet; DeltaDS: TClientDataSet; UpdateKind: TUpdateKind; var Applied: Boolean);
begin
if UpdateKind = ukModify then
begin
qryUpdate.SQL.Text := 'update Customer set City="AAA" where CustNo="1221"';
qryUpdate.ExecSQL;
end;
end;
複製代碼
以上面的例子來看,會先更新客戶資料 Customer,然後再更新訂單資
料 Orders。可是如果更新 Orders 時發生了錯誤,之前對於 Customer
所做的異動卻無法 rollback 了。即使這兩個資料集元件都連結到相同
的 TDatabase 元件也一樣。這樣一來仍然無法達到資料完整性。
解決方案 A:
使用 Dan Miser 的 MIDAS Essensial Pack。使用時需 uses CDSUtil
單元,程式碼可以參考下面的範例:
App server 端:
procedure TMtsDmod.MyApplyUpdates(var vDeltaArray: OleVariant; vProviderArray: OleVariant);
begin
try
CDSApplyUpdates(vDeltaArray, vProviderArray);
SetComplete;
except
SetAbort;
end;
end;
複製代碼
Client 端:
procedure TForm1.btnApplyUpdatesClick(Sender: TObject);
var
cdsArray: array [0..1] of TCLientDataSet;
vDeltaArray: OleVariant;
vProviderArray: OleVariant;
begin
cdsArray[0] := cdsPubs; // Master
cdsArray[1] := cdsTitles; // Detail
vDeltaArray := RetrieveDeltas(cdsArray);
vProviderArray := RetrieveProviders(cdsArray);
DCOMConnection1.AppServer.ApplyUpdates(vDeltaArray, vProviderArray);
ReconcileDeltas(cdsArray, vDeltaArray);
end;
複製代碼
解決方案 B:
不要讓 DataSetProvider 更新資料,讓其連接的資料集元件自行更新資料。首先, DataSetProvider 的 ResolveToDataSet 必須設為 True 。然後在 qryOrders 的 OnUpdateRecord 事件中撰寫更新其他資料表的程式碼,像這樣:
procedure TForm1.qryOrdersUpdateRecord(DataSet: TDataSet; UpdateKind: TUpdateKind; var UpdateAction: TUpdateAction);
begin
if UpdateKind = ukModify then
begin
qryUpdate.SQL.Text := 'update Customer set City="AAA" where CustNo="1221"';
qryUpdate.ExecSQL;
end;
end;
複製代碼
你可以故意讓 Orders 在更新時發生錯誤,看看 Customer 資料表中
CustNo 為 '1221' 的那筆記錄的 City 欄位是否被改為 'AAA',如果
不是的話就表示這個方法的確可行,你可以自行驗證看看。
解決方案 C:
在 dataset provider 的 BeforeUpdateRecord 事件中自行處理掉所有
的更新的工作。例如:
procedure TForm1.dspOrdersBeforeUpdateRecord(Sender: TObject; SourceDS: TDataSet; DeltaDS: TClientDataSet; UpdateKind: TUpdateKind; var Applied: Boolean);
begin
qryCustomer.UpdateObject := usqlCustomer;
usqlCustomer.SetParams(UpdateKind);
usqlCustomer.ExecSQL(UpdateKind);
qryOrders.UpdateObject := usqlOrders;
usqlOrders.SetParams(UpdateKind);
usqlOrders.ExecSQL(UpdateKind);
Applied := True;
end;
複製代碼
使用這個方法時別忘了最後要將 Applied 設為 True, 告訴 dataset provider 你已經完成更新資料的工作。
歡迎光臨 bestlong 怕失憶論壇 (http://www.bestlong.idv.tw/)
Powered by Discuz! X1.5