从两层迁移到三层第一个要面临的窍门就是摆脱在客户端控制事务.客户端不应该开始和提交事务.事实上客户端应该不知道任何事物.所有的事务逻辑应该放在服务端.
本文向你展示如何在RemObjects DataSnap服务中创建一个方法,用以传递一个ClientDataSet. Delta集合并在单独的事务中向数据库中更新,以便于在更新时发生异常时回滚事务.
这个方法只适用于你使用非嵌套(主从关系)的ClientDataSets 的情况,因为DataSnap默认情况下已经在单独事务中使用嵌套(主从关系)数据集.
你现在需要一个RO DataSnap server,由于我不打算介绍如何创建这种服务,所以我们使用一个已经存在的服务.
首先,你需要在服务端RODL中创建一下数据类型.使用RO Service Builder,创建一个包含ProviderName (string) 和 Delta (binary)成员的DeltaToApply结构体:
然后创建DeltaToApply类型的数组:
接下来,在服务端创建接收这个数组的函数.我将这个函数添加到包含所有Provider的同一个服务中,因为我们要使用这个Provider更新数据:
方法实现如下:
procedure TNewService.ApplyUpdates(var ADeltaArray: DeltaArray);
var
I: Integer;
Provider: TDataSetProvider;
ErrorCount: Integer;
begin
// Put your code to start transaction
try
for I := 0 to ADeltaArray.Count - 1 do
begin
Provider := FindProvider(ADeltaArray[I].ProviderName);
if not Assigned(Provider) then
raise Exception.Create('Provider not found: ' + ADeltaArray[I].ProviderName);
Provider.ApplyUpdates(VariantFromBinary(ADeltaArray[I].Delta), 0, ErrorCount);
if ErrorCount > 0 then
// Put your code to handle errors
raise Exception.Create('Errors during applyupdates: ' + Provider.Name);
end;
// Put your code to commit the transaction
except
// Put your code to rollback the transaction
raise;
end;
end;
我已经创建了一个帮助函数去根据名字获取一个Provider:
function TNewService.FindProvider(ProviderName: string): TDataSetProvider;
var
Component: TObject;
begin
Component := FindComponent(ProviderName);
if Component is TDataSetProvider then
Result := Component as TDataSetProvider
else
Result := nil;
end;
服务端完成.在客户端,你需要创建一个方法将所有的ClientDataSet.Delta保存在数组并将其发送到服务端:
procedure TClientForm.ApplyUpdates(ClientDataSets: array of TClientDataSet);
var
Deltas: DeltaArray;
Delta: DeltaToApply;
I: Integer;
begin
Deltas := DeltaArray.Create;
try
for I := Low(ClientDataSets) to High(ClientDataSets) do
begin
if ClientDataSets[I].ChangeCount = 0 then
Continue;
Delta := Deltas.Add;
Delta.ProviderName := ClientDataSets[I].ProviderName;
Delta.Delta := BinaryFromVariant(ClientDataSets[I].Delta);
end;
CoNewService.Create(ROMessage, ROChannel).ApplyUpdates(Deltas);
finally
Deltas.Free;
end;
end;
VariantFromBinary 和 BinaryFromVariant 方法在uROBinaryHelpers单元内.
最后,你只需要在客户端调用这个方法传递所有的你需要在同一个事务中更新的ClientDataSet:
ApplyUpdates([ClientDataSet1, ClientDataSet2, ClientDataSet3]);
好了!我希望这能对你有帮助.如果你发现代码存在问题或有可以改进的地方请尽快通知我以便于修正.
本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/henreash/archive/2008/04/17/2300372.aspx