实体框架交易错误

时间:2016-04-25 15:26:49

标签: c# entity-framework transactions

我正在使用实体框架,我有几种使用事务的方法。我收到此错误:连接已在事务中,无法参与另一个事务。 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 个答案:

答案 0 :(得分:5)

在开启新交易之前,您需要提交前一个交易,因此您不应该在前一个交易中打开新交易。

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();
}

答案 1 :(得分:0)

让我为您提供一个已经回答的问题的替代方法。

您可以检查是否已创建交易,并改为使用它。

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);,它将创建一个新交易并使用它