Browse Source

Fixed #8049: UnitOfWorkDbContextProvider should not reuse the transaction if dbcontext doesn't reuse the connection.

pull/8170/head
Halil İbrahim Kalkan 6 years ago
parent
commit
5d1fb4e434
  1. 2
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/DbContextCreationContext.cs
  2. 10
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/EfCoreTransactionApi.cs
  3. 46
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs

2
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/DbContextCreationContext.cs

@ -13,7 +13,7 @@ namespace Volo.Abp.EntityFrameworkCore.DependencyInjection
public string ConnectionString { get; } public string ConnectionString { get; }
public DbConnection ExistingConnection { get; set; } public DbConnection ExistingConnection { get; internal set; }
public DbContextCreationContext(string connectionStringName, string connectionString) public DbContextCreationContext(string connectionStringName, string connectionString)
{ {

10
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/EfCoreTransactionApi.cs

@ -34,9 +34,10 @@ namespace Volo.Abp.Uow.EntityFrameworkCore
foreach (var dbContext in AttendedDbContexts) foreach (var dbContext in AttendedDbContexts)
{ {
if (dbContext.As<DbContext>().HasRelationalTransactionManager()) if (dbContext.As<DbContext>().HasRelationalTransactionManager() &&
dbContext.Database.GetDbConnection() == DbContextTransaction.GetDbTransaction().Connection)
{ {
continue; //Relational databases use the shared transaction continue; //Relational databases use the shared transaction if they are using the same connection
} }
await dbContext.Database.CommitTransactionAsync(CancellationTokenProvider.Token); await dbContext.Database.CommitTransactionAsync(CancellationTokenProvider.Token);
@ -54,9 +55,10 @@ namespace Volo.Abp.Uow.EntityFrameworkCore
foreach (var dbContext in AttendedDbContexts) foreach (var dbContext in AttendedDbContexts)
{ {
if (dbContext.As<DbContext>().HasRelationalTransactionManager()) if (dbContext.As<DbContext>().HasRelationalTransactionManager() &&
dbContext.Database.GetDbConnection() == DbContextTransaction.GetDbTransaction().Connection)
{ {
continue; //Relational databases use the shared transaction continue; //Relational databases use the shared transaction if they are using the same connection
} }
await dbContext.Database.RollbackTransactionAsync(CancellationTokenProvider.FallbackToProvider(cancellationToken)); await dbContext.Database.RollbackTransactionAsync(CancellationTokenProvider.FallbackToProvider(cancellationToken));

46
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs

@ -105,6 +105,7 @@ namespace Volo.Abp.Uow.EntityFrameworkCore
return (TDbContext)((EfCoreDatabaseApi)databaseApi).DbContext; return (TDbContext)((EfCoreDatabaseApi)databaseApi).DbContext;
} }
[Obsolete("Use CreateDbContextAsync method.")]
private TDbContext CreateDbContext(IUnitOfWork unitOfWork, string connectionStringName, string connectionString) private TDbContext CreateDbContext(IUnitOfWork unitOfWork, string connectionStringName, string connectionString)
{ {
var creationContext = new DbContextCreationContext(connectionStringName, connectionString); var creationContext = new DbContextCreationContext(connectionStringName, connectionString);
@ -145,6 +146,7 @@ namespace Volo.Abp.Uow.EntityFrameworkCore
} }
} }
[Obsolete("Use CreateDbContextAsync.")]
private TDbContext CreateDbContext(IUnitOfWork unitOfWork) private TDbContext CreateDbContext(IUnitOfWork unitOfWork)
{ {
return unitOfWork.Options.IsTransactional return unitOfWork.Options.IsTransactional
@ -159,6 +161,7 @@ namespace Volo.Abp.Uow.EntityFrameworkCore
: unitOfWork.ServiceProvider.GetRequiredService<TDbContext>(); : unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
} }
[Obsolete("Use CreateDbContextWithTransactionAsync.")]
private TDbContext CreateDbContextWithTransaction(IUnitOfWork unitOfWork) private TDbContext CreateDbContextWithTransaction(IUnitOfWork unitOfWork)
{ {
var transactionApiKey = $"EntityFrameworkCore_{DbContextCreationContext.Current.ConnectionString}"; var transactionApiKey = $"EntityFrameworkCore_{DbContextCreationContext.Current.ConnectionString}";
@ -191,7 +194,24 @@ namespace Volo.Abp.Uow.EntityFrameworkCore
if (dbContext.As<DbContext>().HasRelationalTransactionManager()) if (dbContext.As<DbContext>().HasRelationalTransactionManager())
{ {
dbContext.Database.UseTransaction(activeTransaction.DbContextTransaction.GetDbTransaction()); if (dbContext.Database.GetDbConnection() == DbContextCreationContext.Current.ExistingConnection)
{
dbContext.Database.UseTransaction(activeTransaction.DbContextTransaction.GetDbTransaction());
}
else
{
/* User did not re-use the ExistingConnection and we are starting a new transaction.
* EfCoreTransactionApi will check the connection string match and separately
* commit/rollback this transaction over the DbContext instance. */
if (unitOfWork.Options.IsolationLevel.HasValue)
{
dbContext.Database.BeginTransaction(unitOfWork.Options.IsolationLevel.Value);
}
else
{
dbContext.Database.BeginTransactionAsync();
}
}
} }
else else
{ {
@ -239,7 +259,29 @@ namespace Volo.Abp.Uow.EntityFrameworkCore
if (dbContext.As<DbContext>().HasRelationalTransactionManager()) if (dbContext.As<DbContext>().HasRelationalTransactionManager())
{ {
await dbContext.Database.UseTransactionAsync(activeTransaction.DbContextTransaction.GetDbTransaction(), GetCancellationToken()); if (dbContext.Database.GetDbConnection() == DbContextCreationContext.Current.ExistingConnection)
{
await dbContext.Database.UseTransactionAsync(activeTransaction.DbContextTransaction.GetDbTransaction(), GetCancellationToken());
}
else
{
/* User did not re-use the ExistingConnection and we are starting a new transaction.
* EfCoreTransactionApi will check the connection string match and separately
* commit/rollback this transaction over the DbContext instance. */
if (unitOfWork.Options.IsolationLevel.HasValue)
{
await dbContext.Database.BeginTransactionAsync(
unitOfWork.Options.IsolationLevel.Value,
GetCancellationToken()
);
}
else
{
await dbContext.Database.BeginTransactionAsync(
GetCancellationToken()
);
}
}
} }
else else
{ {

Loading…
Cancel
Save