实体框架事务错误

7

我正在使用实体框架,并且有几个方法需要使用事务。我遇到了这个错误:连接已经在一个事务中,无法参与另一个事务。EntityClient不支持并行事务。 我有多个依赖于“MethodB”的方法,如下面的代码示例:

public void MethodA(){
    using (var tran = Db.Database.BeginTransaction()){  
        MethodB();
        var tableARecord = new TableARecord();
        try
        {
            _context.TableAs.Add(tableARecord)
            Db.SaveChanges();
        }
        catch (Exception excp)
        {
            tran.Rollback();
            throw;
        }
    }
 }

 public void MethodC(){
    using (var tran = Db.Database.BeginTransaction()){  
        MethodB();
        //do something else
    }
 }

 public int MethodB(){
    int ret = 0
    //exception happens when starting the transaction below
    using (var tran = Db.Database.BeginTransaction()){  
        //do something else
    }
    return ret;
 }
2个回答

12

在开启新的事务之前,您需要提交上一个事务,因此您不应该在上一个事务中开启新的事务。

public void MethodA(){
    using (var tran = Db.Database.BeginTransaction()){  
        try
        {
            MethodB();
            var tableARecord = new TableARecord();
            _context.TableAs.Add(tableARecord)
            Db.SaveChanges();
        }
        catch (Exception excp)
        {
            tran.Rollback();
            throw;
        }
    }
 }

 public int MethodB(){
    int ret = 0
    //exception happens when starting the transaction below
    // The transaction is already open, you should not open a new one.

    //do something else
    return ret;
  }

但是,你现在的做法是一种反模式。每次没有在事务打开时执行“保存更改”的操作,都将成为一个单独的事务。

你应该做的是在你的业务逻辑中开始事务,并在同一级别提交它。

// Business Logic :
var transaction = Db.Database.BeginTransaction())
try {
     _Repository.MethodA();
     _Repository.MethodB();
     transaction.Commit();
}
catch(){
     transaction.Rollback();
}


//Repository :

public void MethodA(){
    var tableARecord = new TableARecord();
    _context.TableAs.Add(tableARecord)
    Db.SaveChanges();
}

public void MethodA(){
    // Just do some other stuff
    Db.SaveChanges();
}

5

让我为已回答的问题提供一种替代方案。

您可以检查是否已创建交易,然后使用它。

public async Task MethodA()
{
    using(var transaction = await context.BeginTransaction() )
    {
        await MethodB(transaction);

        //...

        transaction.Commit();
    }
}

public async Task MethodB(IDbContextTransaction transaction)
{
    var isOpen = transaction != null;

    try
    {
        if (!isOpen)
        {
            transaction = await context.BeginTransaction();
        }

        //...

        if (!isOpen)
        {
            transaction.Commit();
        }
    }
    finally
    {
        if (!isOpen)
        {
            transaction.Dispose();
        }
    }
}

通过调用MethodA();,它随后调用MethodB(transaction);,将使用当前事务。
通过调用MethodB(null);,将创建一个新的事务并代替当前事务。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接