RO39 – 在一个事务中实现多个ClientDataSets 更新
作者
Erick Sasse (
葡萄牙语版本
www.ericksasse.com.br)
RemObjects
提示
:
我们相信本文是正确的
,
但我们不做任何保证
.
在此感谢
Erick Sasse
写的文章
,
很高兴在此发表
.
从两层迁移到三层第一个要面临的窍门就是摆脱在客户端控制事务
.
客户端不应该开始和提交事务
.
事实上客户端应该不知道任何事物
.
所有的事务逻辑应该放在服务端
.
本文向你展示如何在
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]);
好了
!
我希望这能对你有帮助
.
如果你发现代码存在问题或有可以改进的地方请尽快通知我以便于修正
.