dotnet / dotnet/efcore

EF Core upgrades to a distributed transaction when the TransactionScope contains multiple dbcontexts even if enlist is false

Open
#31,544 4 comments 0 reactions 0 assignees View on GitHub
area-save-changes customer-reported
Dominant language
C#
Stars
14.8k
Forks
3.4k
PR merge metrics
PR metrics pending

Description

After migrating from ef6 to efcore, when there are multiple DbContexts in the TransactionScope (even if they share the same connection), it returns an error the second time SaveChanges, even if enlist is false.

Refer to the document after set up the Database. AutoTransactionBehavior = AutoTransactionBehavior. Never. It didn't work either.

ef6 does not have this problem.

Specific stack:
``` text
Unhandled exception. System.InvalidOperationException: A root ambient transaction was completed before the nested transaction. The nested transactions should be completed first.
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.HandleTransactionCompleted(Object sender, TransactionEventArgs e)
at System.Transactions.InternalTransaction.FireCompletion()
at System.Transactions.TransactionStateAborted.EnterState(InternalTransaction tx)
at System.Transactions.TransactionStatePromotedBase.ChangeStateAbortedDuringPromotion(InternalTransaction tx)
at System.Transactions.TransactionStateDelegatedBase.EnterState(InternalTransaction tx)
at System.Transactions.EnlistableStates.Promote(InternalTransaction tx)
at System.Transactions.Transaction.Promote()
at System.Transactions.TransactionInterop.ConvertToDistributedTransaction(Transaction transaction)
at System.Transactions.TransactionInterop.GetExportCookie(Transaction transaction, Byte[] whereabouts)
at Microsoft.Data.SqlClient.SqlInternalConnection.GetTransactionCookie(Transaction transaction, Byte[] whereAbouts)
at Microsoft.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx)
at Microsoft.Data.SqlClient.SqlInternalConnection.Enlist(Transaction tx)
at Microsoft.Data.SqlClient.SqlInternalConnection.EnlistTransaction(Transaction transaction)
at Microsoft.Data.SqlClient.SqlConnection.EnlistTransaction(Transaction transaction)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.ConnectionEnlistTransaction(Transaction transaction)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.HandleAmbientTransactions()
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.Open(Boolean errorsExpected)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable`1 commandBatches, IRelationalConnection connection)
at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChanges(IList`1 entries)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IList`1 entriesToSave)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(StateManager stateManager, Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.<>c.b__107_0(DbContext _, ValueTuple`2 t)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.DbContext.SaveChanges()
at Program.$(String[] args) in C:\Users\yxcha\Desktop\EfcoreDemo\Program.cs:line 20
```
Code :
Model
``` cshap
[Table("testTable", Schema = "dbo")]
public class TestModel
{
public TestModel(string code, string name)
{
this.Code = code;
this.Name = name;
this.CreateTime = DateTime.Now;
}

[Key]
[MaxLength(36)]
public string Code { get; set; }
[MaxLength(50)]
public string Name { get; set; }
public DateTime CreateTime { get; set; }
}
```
DbContext
``` cshap
public class TestDbContext:DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("server=localhost;database=testDb;User ID=test;Password=123456;enlist=false;TrustServerCertificate=true;");
base.OnConfiguring(optionsBuilder);
}

public virtual DbSet TestModels { get; set; }
}
```
Program
``` cshap
using (var tran = new TransactionScope())
{

using (var context1 = new TestDbContext())
{
string code = Guid.NewGuid().ToString();
context1.TestModels.Add(new TestModel(code, $"test_{code}"));
context1.SaveChanges();
}

using (var context2 = new TestDbContext())
{
string code = Guid.NewGuid().ToString();
context2.TestModels.Add(new TestModel(code, $"test_{code}"));
context2.SaveChanges();
}
}
```

Example: [EfcoreDemo.zip](https://github.com/dotnet/efcore/files/12426539/EfcoreDemo.zip)

EF Core version:7.0.5
Database provider: (e.g. Microsoft.EntityFrameworkCore.SqlServer:7.0.5)
Target framework: (e.g. .NET 6.0)
Operating system:
IDE: (e.g. Visual Studio 2022 17.5)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.