diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs index d46893d590..508fb1db4f 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs @@ -15,6 +15,10 @@ namespace Volo.Abp.Uow public bool IsReserved => _parent.IsReserved; + public bool IsDisposed => _parent.IsDisposed; + + public bool IsCompleted => _parent.IsCompleted; + public string ReservationName => _parent.ReservationName; public event EventHandler Failed; diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs index 6fe2546965..cdf1a505b8 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs @@ -20,6 +20,10 @@ namespace Volo.Abp.Uow bool IsReserved { get; } + bool IsDisposed { get; } + + bool IsCompleted { get; } + string ReservationName { get; } void SetOuter([CanBeNull] IUnitOfWork outer); diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs index 3f5a9cebf7..f6501ae833 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs @@ -18,6 +18,10 @@ namespace Volo.Abp.Uow public bool IsReserved { get; set; } + public bool IsDisposed { get; private set; } + + public bool IsCompleted { get; private set; } + public string ReservationName { get; set; } protected List> CompletedHandlers { get; } = new List>(); @@ -32,8 +36,7 @@ namespace Volo.Abp.Uow private readonly UnitOfWorkDefaultOptions _defaultOptions; private Exception _exception; - private bool _isCompleted; - private bool _isDisposed; + private bool _isCompleting; private bool _isRolledback; public UnitOfWork(IServiceProvider serviceProvider, IOptions options) @@ -101,8 +104,10 @@ namespace Volo.Abp.Uow try { + _isCompleting = true; SaveChanges(); CommitTransactions(); + IsCompleted = true; OnCompleted(); } catch (Exception ex) @@ -123,8 +128,10 @@ namespace Volo.Abp.Uow try { + _isCompleting = true; await SaveChangesAsync(cancellationToken); await CommitTransactionsAsync(); + IsCompleted = true; await OnCompletedAsync(); } catch (Exception ex) @@ -250,16 +257,16 @@ namespace Volo.Abp.Uow public virtual void Dispose() { - if (_isDisposed) + if (IsDisposed) { return; } - _isDisposed = true; + IsDisposed = true; DisposeTransactions(); - if (!_isCompleted || _exception != null) + if (!IsCompleted || _exception != null) { OnFailed(); } @@ -283,15 +290,12 @@ namespace Volo.Abp.Uow private void PreventMultipleComplete() { - if (_isCompleted) + if (IsCompleted || _isCompleting) { throw new AbpException("Complete is called before!"); } - - _isCompleted = true; } - protected virtual void RollbackAll() { foreach (var databaseApi in _databaseApis.Values) diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkManager.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkManager.cs index 447a6c182e..4523f8f8f7 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkManager.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkManager.cs @@ -23,9 +23,10 @@ namespace Volo.Abp.Uow { Check.NotNull(options, nameof(options)); - if (!requiresNew && _ambientUnitOfWork.UnitOfWork != null && !_ambientUnitOfWork.UnitOfWork.IsReserved) + var currentUow = Current; + if (currentUow != null && !requiresNew) { - return new ChildUnitOfWork(_ambientUnitOfWork.UnitOfWork); + return new ChildUnitOfWork(currentUow); } var unitOfWork = CreateNewUnitOfWork(); @@ -86,7 +87,7 @@ namespace Volo.Abp.Uow var uow = _ambientUnitOfWork.UnitOfWork; //Skip reserved unit of work - while (uow != null && uow.IsReserved) + while (uow != null && (uow.IsReserved || uow.IsDisposed || uow.IsCompleted)) { uow = uow.Outer; } diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/EntityFrameworkCoreTestBase.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/EntityFrameworkCoreTestBase.cs index 17480a6f48..87bd7cfc28 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/EntityFrameworkCoreTestBase.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/EntityFrameworkCoreTestBase.cs @@ -1,9 +1,4 @@ -using System; -using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.Uow; - -namespace Volo.Abp.EntityFrameworkCore +namespace Volo.Abp.EntityFrameworkCore { public abstract class EntityFrameworkCoreTestBase : AbpIntegratedTest { diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Uow/Uow_Completed_Tests.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Uow/Uow_Completed_Tests.cs new file mode 100644 index 0000000000..f7e5019467 --- /dev/null +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Uow/Uow_Completed_Tests.cs @@ -0,0 +1,9 @@ +using Volo.Abp.TestApp.Testing; + +namespace Volo.Abp.EntityFrameworkCore.Uow +{ + public class Uow_Completed_Tests : Uow_Completed_Tests + { + + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Uow/Uow_Completed_Tests.cs b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Uow/Uow_Completed_Tests.cs new file mode 100644 index 0000000000..4773644885 --- /dev/null +++ b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Uow/Uow_Completed_Tests.cs @@ -0,0 +1,9 @@ +using Volo.Abp.TestApp.Testing; + +namespace Volo.Abp.MongoDB.Uow +{ + public class Uow_Completed_Tests : Uow_Completed_Tests + { + + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Uow_Completed_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Uow_Completed_Tests.cs new file mode 100644 index 0000000000..1b169bbe97 --- /dev/null +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Uow_Completed_Tests.cs @@ -0,0 +1,40 @@ +using System; +using System.Threading.Tasks; +using Volo.Abp.Modularity; +using Volo.Abp.TestApp.Domain; +using Volo.Abp.Uow; +using Xunit; + +namespace Volo.Abp.TestApp.Testing +{ + public abstract class Uow_Completed_Tests : TestAppTestBase + where TStartupModule : IAbpModule + { + private readonly IUnitOfWorkManager _unitOfWorkManager; + private readonly ICityRepository _cityRepository; + + protected Uow_Completed_Tests() + { + _unitOfWorkManager = GetRequiredService(); + _cityRepository = GetRequiredService(); + } + + [Fact] + public async Task Should_Be_Able_To_Perform_Database_Operation_On_Uow_Complete() + { + using (var uow = _unitOfWorkManager.Begin()) + { + //Perform an arbitrary database operation + await _cityRepository.InsertAsync(new City(Guid.NewGuid(), Guid.NewGuid().ToString())); + + uow.OnCompleted(async () => + { + //Perform another database operation inside the OnCompleted handler + await _cityRepository.InsertAsync(new City(Guid.NewGuid(), Guid.NewGuid().ToString())); + }); + + await uow.CompleteAsync(); + } + } + } +}