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. I have multiple methods depending on 'MethodB' like the code example below:
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();
that consequently calls MethodB(transaction);
, it will use the current transaction
By calling MethodB(null);
, it will create a new transaction and use it instead
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With