[英]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
有时是独立于MethodA
和MethodC
,并且需要将其工作包装在事务中(如@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.