【问题标题】:Using TransactionScope with two DBContext, get error使用带有两个 DBContext 的 TransactionScope,得到错误
【发布时间】:2016-10-25 18:11:25
【问题描述】:

我有一个使用TransactionScope 的函数。当我使用两个dbContext 时,它会崩溃。错误信息是:

System.Data.EntityException: Error underlying provider Open. ---> System.Transactions.TransactionException: The operation is not valid for the state of the transaction. in System.Transactions.TransactionState.EnlistPromotableSinglePhase (InternalTransaction tx, IPromotableSinglePhaseNotification promotableSinglePhaseNotification, Transaction AtomicTransaction, Guid promoterType) in System.Transactions.Transaction.EnlistPromotableSinglePhase (IPromotableSinglePhaseNotification promotableSinglePhaseNotification, Guid promoterType) in System.Transactions.Transaction.EnlistPromotableSinglePhase (IPromotableSinglePhaseNotification promotableSinglePhaseNotification) in System .Data.SqlClient.SqlInternalConnection.EnlistNonNull (Transaction tx) in System.Data.SqlClient.SqlInternalConnection.Enlist (Transaction tx)
in System.Data.ProviderBase.DbConnectionInternal.ActivateConnection (Transaction transaction) in System.Data.ProviderBase.DbConnectionPool.PrepareConnection (DbConnection owningObject, DbConnectionInternal obj, Transaction transaction) in System.Data.ProviderBase.DbConnectionPool.TryGetConnection (DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout , allowCreate Boolean, Boolean onlyOneCheckConnection, DbConnectionOptions UserOptions, DbConnectionInternal & connection) in System.Data.ProviderBase.DbConnectionPool.TryGetConnection (DbConnection owningObject, TaskCompletionSource1 retry, DbConnectionOptions
  UserOptions, DbConnectionInternal & connection) in
  System.Data.ProviderBase.DbConnectionFactory.TryGetConnection (DbConnection
  owningConnection, TaskCompletionSource1 retry, DbConnectionOptions UserOptions, DbConnectionInternal oldConnection, DbConnectionInternal & connection) in System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal (DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource1 retry, DbConnectionOptions UserOptions) in
  System.Data.SqlClient.SqlConnection.TryOpenInner (TaskCompletionSource1 retry) in System.Data.SqlClient.SqlConnection.TryOpen (TaskCompletionSource`1 retry) in System.Data.SqlClient.SqlConnection.Open () in System.Data.EntityClient.EntityConnection. OpenStoreConnectionIf (Boolean openCondition, DbConnection storeConnectionToOpen, DbConnection originalConnection, String ExceptionCode, attemptedOperation String, Boolean & closeStoreConnectionOnFailure)

代码

public void example(int c, IEnumerable<int> pi, string comm)
{
    using (var transactionScope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead }))
    {
        var idsList = pi.ToList();
        foreach (var playlist in Context.pl.Where(p => idsList.Contains(p.pid) && p.c== c&& p.stat== 1))
        {
            playlist.TimestampAuthorized = null;

            var pl = "sss";
            notif.generateNotifForUser((new Notification(1, 1, pl, 2, 2)));
        }
        Context.SaveChanges();
        transactionScope.Complete();
    }
}

问题出现在Context.SaveChanges(); 如果我评论notif.generateNotifForUser(); 行,它会起作用。进入那个函数,我也做context.saveChanges();

谢谢

【问题讨论】:

  • 了解异常的详细信息会很有帮助,例如其类型、消息等。
  • 我已添加到帖子中。
  • 能否提供英文的异常信息。
  • 如果 notif.generateNotifForUser((new Notification(1, 1, pl, 2, 2))); 导致错误,那么您需要向我们展示该方法是什么样的

标签: c# entity-framework transactionscope


【解决方案1】:
// code before unchanged
foreach (var playlist in Context.pl.Where(p => idsList.Contains(p.pid) && p.c== c&& p.stat== 1).ToList()) // added ToList
// code after unchanged

问题与您尝试将开放连接用于两件事的事实有关。迭代 pl DbSet 结果以及您在 generateNotifForUser 中所做的任何事情,这可能是您从 DbContext 获取/执行其他操作的地方(根据您的更新,您正在调用 SaveChanges)。要解决此问题,请在您的 Lamda 语句末尾添加 ToList 以强制在迭代开始之前立即完全实现查询结果。然后连接将不再打开,允许您在代码的其他部分继续使用DbContext。这还假设您没有在方法链的下游犯下类似的错误。

【讨论】:

    【解决方案2】:

    编辑:

    通知方法似乎导致了错误,因为它也调用了Context.SaveChanges

    您只需拨打Context.SaveChanges一次

    我会删除通知方法中的Context.SaveChanges,只在事务范围结束时调用它一次。

    【讨论】:

    • "你不应该在这样的 foreach 循环中访问上下文。" 为什么
    • 当您尝试在 foreach 循环中枚举 IEnumerable 时会出现类似的问题。每次迭代循环时,它都会尝试枚举。
    • 我们这个职业的好处是代码是可预测的。 “奇怪的事情”不仅会发生,组件或代码的行为方式总是有原因的。我还没有遇到无法以逻辑方式解释的一段代码的问题。在答案中添加“奇怪的事情发生在……时”只会使其后面的所有其他内容无效(IMO)。
    • 好的,我会复制我的评论并将其粘贴到帖子中,以安抚我们行业中的人,比如你自己。编辑:没关系。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-08
    • 2018-04-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多