RO39 – 在一个事务中实现多个ClientDataSets 更新
2014-05-07 20:45
465 查看
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]);
好了!我希望这能对你有帮助.如果你发现代码存在问题或有可以改进的地方请尽快通知我以便于修正.
作者 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]);
好了!我希望这能对你有帮助.如果你发现代码存在问题或有可以改进的地方请尽快通知我以便于修正.
相关文章推荐
- RO39 – 在一个事务中实现多个ClientDataSets 更新
- RO39 – 在一个事务中实现多个ClientDataSets 更新
- RemObject 在一个事务中实现多个clientdataset的更新
- Struts2+Ibatis+Spring.30(完整例子,含3.0事务配置,OSCache缓存配置,JreeChart配置,log4j日志输出Sql,对一个表实现完整的查询,批量删除,添加,更新)
- DNS Tunneling及相关实现——总之,你发起攻击都需要一个DNS server,下载一些工具作为client发起数据,server收集数据并响应
- 一个简单的存储过程(实现事务执行两个sql语句,修改可实现执行更多条sql语句)
- 实现iOS图片等资源文件的热更新化(四): 一个最小化的补丁更新逻辑
- 使用事务与锁,实现一个用户取过的数据不被其他用户取到
- C语言实现的计算一个文件下的所有文件的总大小(还有BUG,如果文件夹下面还有文件家就有问题,等待更新)
- 使用jQuery实现一个类似GridView的编辑,更新,取消和删除的功能
- 用Application Updater Block生成一个自我更新的WinForms 应用(amart client)
- 一个简单的脚本,实现自动执行MITM攻击(更新0.2)
- QNJR-GROUP/EasyTransaction: 依赖于Spring的一个柔性事务实现,包含 TCC事务,补偿事务,基于消息的最终一致性事务,基于消息的最大努力交付事务交付QNJR-GROUP/EasyTransaction: 依赖于Spring的一个柔性事务实现,包含 TCC事务,补偿事务,基于消息的最终一致性事务,基于消息的最大努力交付事务交付
- 用C语言实现一个简单的HTTP客户端(HTTP Client)
- Delphi XE8 利用HttpClient实现的一个App自动更新组件
- 一个简单的分布式事务系统的实现(订单系统)
- .NET一个线程更新另一个线程的UI(两种实现方法及若干简化)
- JSPatch库, 一个Apple官方支持的实现在线更新iOS应用的库
- 1模拟网易邮箱实现全选,全不的功能(服务端和客户端) 2 使用DataList实现 加入购物车,编辑,删除,更新,取消功能。要求连一个产品表。
- MERGE--一个语句实现存在就更新,不存在就插入