简体   繁体   English

实体框架事务错误

[英]entity framework transaction error

I am using entity framework and I have several methods where I am using transactions.我正在使用实体框架,并且有几种使用事务的方法。 I get this error: The connection is already in a transaction and cannot participate in another transaction.我收到这个错误:连接已经在一个事务中,不能参与另一个事务。 EntityClient does not support parallel transactions. EntityClient 不支持并行事务。 I have multiple methods depending on 'MethodB' like the code example below:我有多种方法取决于“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;
 }

Before opening a new transaction, you need to commit the previous one, so you should not have opened a new transaction inside the previous one.在打开一个新的事务之前,你需要提交前一个,所以你不应该在前一个里面打开一个新的事务。

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

but, the way you are doing it is an anti pattern.但是,你这样做的方式是一种反模式。 Every "save changes" that is not made when a transaction is opened, will be a single transaction.打开事务时未进行的每个“保存更改”都将是单个事务。

The thing you should do is to begin your transaction inside your Business logic, and commit it at the same level.您应该做的是在您的业务逻辑中开始您的事务,并在同一级别提交它。

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

Let me provide you an alternative for the already answered question.让我为您提供已回答问题的替代方案。

You could check if a transaction is already created and use it instead.您可以检查是否已创建事务并使用它。

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

By calling MethodA();通过调用MethodA(); that consequently calls MethodB(transaction);因此调用MethodB(transaction); , it will use the current transaction ,它将使用当前事务

By calling MethodB(null);通过调用MethodB(null); , it will create a new transaction and use it instead ,它将创建一个新事务并使用它代替

If MethodB is sometimes called independently of MethodA and MethodC , and it needs to wrap its work in a transaction (as pointed out by @Deblaton Jean-Philippe, you don't need a transaction if the method only calls SaveChanges once), it can check to see if a transaction already exists, and create one if it doesn't, like this: 如果MethodB有时是独立于MethodAMethodC ,并且需要将其工作包装在事务中(如@Deblaton Jean-Philippe所指出的,如果该方法仅调用一次SaveChanges则不需要事务),它可以检查是否存在事务,如果没有,则创建一个事务,如下所示:

public int MethodB(){
   int ret = 0
   using (var tran = Db.Database.CurrentTransaction ?? Db.Database.BeginTransaction()) 
   {  
       //do something else
   }
   return ret;
} 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM