WF4 TransactionScope包含多个具有EF4数据库更新的自定义活动

时间:2012-10-08 08:10:19

标签: entity-framework transactions workflow-foundation-4

我使用实体框架4和POCO创建了几个自定义活动,用于更新数据库中的表(在本例中为SQL Server Compact)。

如果我在WF4 TransactionScope活动中放入了多个这样的问题,我遇到了问题:EF在第一个活动完成后处理数据库连接,并且当下一个数据库活动尝试进行数据库更新时建立连接。此时会抛出异常。

System.Activities.WorkflowApplicationAbortedException : The workflow has been aborted.
 ----> System.Data.EntityException : The underlying provider failed on Open.
 ----> System.InvalidOperationException : The connection object can not be enlisted in transaction scope.

在整个交易范围内,我是否必须保持EF连接处于打开状态?我怎样才能做到这一点?为此创建一个显式的自定义活动,还是有一种标准方式?

我当前的解决方法是这样的:我创建了一个新的代码活动,它创建了我们的ObjectContext并且明确地调用了dbContext.Connection.Open()。它返回ObjectContext,然后将其保存在工作流变量中。那个作为InArgument<>传递给所有与DB相关的活动。在我的数据库活动中,如果传入它,我会使用此ObjectContext,否则我会创建一个新的。

这确实有效,但我对此解决方案不满意:它需要针对每个数据库相关活动的新InArgument。在工作流设计器中,我必须在事务范围内插入特殊的OpenDatabaseConnection活动,然后确保将正确的变量传递到所有数据库活动中。这似乎非常不优雅且容易出错,特别是如果其他团队成员必须使用这些数据库活动。

处理此事的更好方法是什么?

1 个答案:

答案 0 :(得分:1)

问题在于,当您在同一事务范围中打开第二个连接时,会尝试将事务提升为分布式事务(即使连接到同一数据库,也没有任何内容分发)。 SQL Server CE不支持此方案。

我要做的是创建一个自定义的“容器”活动,该活动打开(并关闭)连接并使其可用于子活动。这仍然不是最佳的,但至少你不再需要通过InArgument了。您将获得以下活动树:

TransactionScope
    InitializeConnection
        Sequence
            CustomDataActivity1
            CustomDataActivity2
            CustomDataActivity3

InitializeConnection是一个NativeActivity,它使用NativeActivityContext.Properties向子活动公开连接(或ObjectContext)。

确保您实施正确的错误处理,以确保您始终关闭连接。

注意:仅通过名为MSDTC(Microsoft分布式事务处理协调器)的Windows服务,完整SQL Server支持分布式事务。您可以在“本地服务”中找到这个。由于SQL Server CE是一个应该能够完全独立运行的数据库,因此它不依赖于MSDTC是有道理的。因此它不支持分布式事务。