通过WCF实现LINQ-to-SQL事务

时间:2009-04-15 20:36:33

标签: wcf web-services linq-to-sql

我有一个WCF服务,用于向数据库添加投标,即MS SQL Server 2005.WCF使用LINQ-to-SQL。

每个招标都可以有很多文件和很多项目。客户可以为每个服务调用添加一个对象。也就是说,做这样的事情:

TendersServiceClient service = new TenderServiceClient();
service.BeginTransaction();

// Adding a new tender
service.AddTender(TenderDTO tenderInfo);

// Adding tender's documents
foreach (DocumentDTO documentInfo in documents)
   service.AddTenderDocument(tenderInfo.TenderID, documentInfo);

// Adding tender's items
foreach (ItemDTO itemInfo in items)
   service.AddTenderItem(tenderInfo.TenderID, itemInfo);

service.CommitTransaction();

注意BeginTransaction()和CommitTransaction()。也就是说,所有上述过程必须完全成功或完全回滚。例如,如果其中一个项目无法插入,那么整个招标就不应该存在......

所以问题是如何实现这种交易。问题是WCF当然是无国籍的。因此,为每个服务调用创建了新的DataContext。如果我使用静态DataContext,那么我将能够使用其内置的事务功能,但是如何处理其他可以尝试同时添加另一个招标的客户(当然,他们必须在这笔交易之外)?

所以请帮助我用某种设计模式来实现这一目标。我可以自由更改服务和客户端的代码,所以请随意使用您的建议=)

2 个答案:

答案 0 :(得分:2)

您是否控制了服务的界面?

如果是这样,那么优雅的解决方案肯定是服务在单个方法中接受聚合Tender对象,而不是现在拥有的chatty方法。然后,投标将具有项目和文档作为子集合,并且数据访问代码可以更容易地处理单个事务中的所有更新。

除非我误解,否则它似乎非常类似于Order / OrderDetails场景,其中适用相同的逻辑。

答案 1 :(得分:1)

首先,你必须在这里使用交易服务电话 - 因为你有一个“初始化”电话,一堆中间电话,然后可能有一个结束所有电话,我建议你看看方法的OperationContract上的“IsInitiating”和“IsTerminating”属性 - 这将允许您指定一个方法来启动会话,并指定一个方法来完成它。

接下来,请确保将服务配置为事务服务,方法是将“TransactionFlow”属性放在服务或所有操作上 - 无论您喜欢哪种操作。

在您的客户端代码中,您必须使用System.Transactions创建一个TransactionScope,它将包装您的服务调用。这是一个轻量级或完全两阶段的分布式事务协调器 - 具体取决于您的调用的详细信息。

沿着这些方向:

1)将您的绑定标记为事务性:

<bindings>
  <wsHttpBinding>
    <binding name="TransactionalWsHttp" transactionFlow="true" />
  </wsHttpBinding>
</bindings>

2)服务合同:

[ServiceContract]
public interface ITenderService
{
  // method to start your submission process
  [OperationContract(IsInitiating=true, IsTerminating=false)]
  [TransactionFlow(TransactionFlowOption.Mandatory]
  public void StartTenderProcess();

  // all your other methods "in between"
  [OperationContract(IsInitiating=false, IsTerminating=false)]
  [TransactionFlow(TransactionFlowOption.Mandatory]
  public void AddTender()

  [OperationContract(IsInitiating=false, IsTerminating=false)]
  [TransactionFlow(TransactionFlowOption.Mandatory]
  public void AddTenderDocument()

  [OperationContract(IsInitiating=false, IsTerminating=false)]
  [TransactionFlow(TransactionFlowOption.Mandatory]
  public void AddTenderItem()

  ...

  // method to end your submission process
  [OperationContract(IsInitiating=false, IsTerminating=true)]
  [TransactionFlow(TransactionFlowOption.Mandatory]
  public void FinishTenderProcess();
}

3)在您的客户代码中:

using (TransactionScope ts = new TransactionScope())
{
   serviceClient.StartTenderProcess();

   ..... 

   serviceClient.FinishTenderProcess();

   ts.Complete();   // Transaction Commit 
}

这有助于你暂时开始吗?

马克