我应该如何将SqlTransaction遗留代码与TranactionScope集成?

时间:2010-01-04 17:02:28

标签: .net linq-to-sql transactions

我有一个使用大量SqlTranaction调用的现有应用程序。构建应用程序的方式我们得到了一堆看起来有点像这样的代码(为简洁起见,删除了错误处理等):

Using transaction As SqlTransaction = Database.CreateSqlTransaction()
    If Not Me.FitnessSession.FitnessTestSessionID.HasValue Then
        Me.FitnessSession.Insert(transaction)
    Else
        Me.FitnessSession.Update(transaction)
    End If
    SaveTestScores(transaction)

    Database.CommitTransaction(transaction) 'This essentially just calls transaction.Commit()

 End Using

我们正在放弃手动滚动的DAL并转移到Linq to SQL,但这将是渐进的,因为我们没有预算来简单地抛弃我们所有的遗留代码。因此,我们将需要在同一事务中使用旧代码和Linq to SQL代码的区域。我相信这可以这样做:

Using scope As New TransactionScope()
Using transaction As SqlTransaction = Database.CreateSqlTransaction()
    If Not Me.FitnessSession.FitnessTestSessionID.HasValue Then
        Me.FitnessSession.Insert(transaction)
    Else
        Me.FitnessSession.Update(transaction)
    End If
    SaveTestScores(transaction)

    Database.CommitTransaction(transaction)

 End Using
 End Using

我不清楚哪个是致电,我是否必须致电scope.Complete()Database.CommitTransaction(transaction)?或者是否有其他选项将两位代码链接在一起?

跟进问题
感谢@ programming-hero,这真的很有帮助,我现在不确定的是,什么时候应该关闭sql连接? DAL方法中的代码检查它是否已通过事务,如果有,则它使用该事务上的连接,并且一旦完成就不关闭连接,如果没有传递任何事务则为新连接打开和关闭以进行操作。如果我在TransactionScope中关闭SqlConnection,这会导致环境事务的问题吗?我问,因为如果我关闭一个具有SqlTransaction对象的SqlConnection,事务就会被回滚。

1 个答案:

答案 0 :(得分:2)

System.Transactions命名空间的目的是允许您在整个应用程序中控制单个模型的事务。使用System.Transactions提供的事务模型时,应避免使用任何显式事务,例如SqlTransaction;在显式交易中混合将使您的生活变得更加困难,因为您必须手动管理这两种模型。

给您带来的好消息:当您使用ADO.NET组件时,您将获得对内置环境事务的支持。这意味着您可以删除对SqlTransaction的所有引用和传递事务对象,因为System.Transactions模型将为您处理所有事情。

环境事务模型用作各种其他特定事务的包装器和协调器。 ADO.NET组件知道查找环境事务并在内部设置自己的特定事务(如SqlTransaction)。 System.Transactions组件会将所有登记的交易警告到TransactionScope区块管理的“全局”交易的状态。

如果您的代码在TransactionScope块内执行,则会有一个环境事务可供事务感知组件参与。对于您的数据访问代码,所有交互都将在同一事务中发生,无论它们是您自己的DAL还是Linq to SQL组件的一部分。您需要知道的是,无论何时出现,他们都会参加环境交易。

要成功完成TransactionScope阻止,只需在工作结束时在本地实例上调用TransactionScope.Complete()即可。为您在其中工作的每个块执行此操作,并在最顶层块完成时,物理事务将提交。

无需调用任何其他特定于交易的代码,因为他们应该(幕后)与您的System.Transaction进行协调。

考虑到所有这些,您的代码可能如下所示:

Using scope As New TransactionScope()

    If Not Me.FitnessSession.FitnessTestSessionID.HasValue Then
        Me.FitnessSession.Insert()
    Else
        Me.FitnessSession.Update()
    End If

    SaveTestScores()

    scope.Complete()

End Using

对数据库特定事务的所有引用都消失了。所有操作都将在TransactionScope提供的环境事务中进行。在此块中,您还可以使用SqlCommand进行直接调用,或使用Linq-to-SQL对象而不指定任何显式事务,并且它们将参与环境事务。