RO39 – 在一个事务中实现多个ClientDataSets 更新

  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 结构体 :
RO39 – 在一个事务中实现多个ClientDataSets 更新_第1张图片
然后创建 DeltaToApply 类型的数组 :

RO39 – 在一个事务中实现多个ClientDataSets 更新_第2张图片

接下来 , 在服务端创建接收这个数组的函数 . 我将这个函数添加到包含所有 Provider 的同一个服务中 , 因为我们要使用这个 Provider 更新数据 :
RO39 – 在一个事务中实现多个ClientDataSets 更新_第3张图片
方法实现如下
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]);
好了 ! 我希望这能对你有帮助 . 如果你发现代码存在问题或有可以改进的地方请尽快通知我以便于修正 .
 
 

你可能感兴趣的:(数据库,String,function,server,service)