From 6f0fdb894dd660fce98f741dcb5097c4da64172e Mon Sep 17 00:00:00 2001 From: Alexander Romanchuk Date: Wed, 15 Feb 2023 19:02:09 +0200 Subject: [PATCH 1/3] Add transaction to blocking Provider --- .../Services/ProviderService.cs | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/OutOfSchool/OutOfSchool.WebApi/Services/ProviderService.cs b/OutOfSchool/OutOfSchool.WebApi/Services/ProviderService.cs index 3623e800d8..46740a4955 100644 --- a/OutOfSchool/OutOfSchool.WebApi/Services/ProviderService.cs +++ b/OutOfSchool/OutOfSchool.WebApi/Services/ProviderService.cs @@ -303,22 +303,24 @@ public async Task Block(ProviderBlockDto providerBlockDto) // TODO: validate if current user has permission to block/unblock the provider provider.IsBlocked = providerBlockDto.IsBlocked; provider.BlockReason = providerBlockDto.IsBlocked ? providerBlockDto.BlockReason : null; - await providerRepository.UnitOfWork.CompleteAsync().ConfigureAwait(false); - - // TODO What's happen if previous action will not successfull? - var workshops = await workshopServiceCombiner - .BlockByProvider(provider) - .ConfigureAwait(false); - foreach (var workshop in workshops) + return await providerRepository.RunInTransaction(async () => { - logger.LogInformation($"IsBlocked property with povider Id = {provider.Id} " + - $"in workshops with Id = {workshop.Id} updated successfully."); - } + await providerRepository.UnitOfWork.CompleteAsync().ConfigureAwait(false); - logger.LogInformation($"Provider(id) {providerBlockDto.Id} IsBlocked was changed to {provider.IsBlocked}"); + var workshops = await workshopServiceCombiner + .BlockByProvider(provider) + .ConfigureAwait(false); + + foreach (var workshop in workshops) + { + logger.LogInformation($"IsBlocked property with povider Id = {provider.Id} " + + $"in workshops with Id = {workshop.Id} updated successfully."); + } - return providerBlockDto; + logger.LogInformation($"Provider(id) {providerBlockDto.Id} IsBlocked was changed to {provider.IsBlocked}"); + return providerBlockDto; + }); } public async Task UpdateLicenseStatus(ProviderLicenseStatusDto dto, string userId) From 207b665cddb249a717983588281f00c968590860 Mon Sep 17 00:00:00 2001 From: Alexander Romanchuk Date: Wed, 15 Feb 2023 22:08:03 +0200 Subject: [PATCH 2/3] Fix test --- .../OutOfSchool.WebApi.Tests/Services/ProviderServiceTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OutOfSchool/OutOfSchool.WebApi.Tests/Services/ProviderServiceTests.cs b/OutOfSchool/OutOfSchool.WebApi.Tests/Services/ProviderServiceTests.cs index 1dbd74b88c..53150ced86 100644 --- a/OutOfSchool/OutOfSchool.WebApi.Tests/Services/ProviderServiceTests.cs +++ b/OutOfSchool/OutOfSchool.WebApi.Tests/Services/ProviderServiceTests.cs @@ -939,6 +939,8 @@ public async Task Block_ReturnsProviderBlockDto_IfDtoIsValid() .ReturnsAsync(provider); providersRepositoryMock.Setup(r => r.UnitOfWork.CompleteAsync()) .ReturnsAsync(It.IsAny()); + providersRepositoryMock.Setup(r => r.RunInTransaction(It.IsAny>>())) + .ReturnsAsync(providerBlockDto); // Act var result = await providerService.Block(providerBlockDto).ConfigureAwait(false); From 6ecce1c0432a73bf6258d92068323d0a1add6138 Mon Sep 17 00:00:00 2001 From: Alexander Romanchuk Date: Fri, 17 Feb 2023 01:03:16 +0200 Subject: [PATCH 3/3] Add RunInTransaction without result --- .../Repository/EntityRepositoryBase.cs | 22 +++++++++++++++++++ .../Repository/IEntityRepository.cs | 7 ++++++ .../Services/ProviderService.cs | 6 +++-- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/OutOfSchool/OutOfSchool.DataAccess/Repository/EntityRepositoryBase.cs b/OutOfSchool/OutOfSchool.DataAccess/Repository/EntityRepositoryBase.cs index fe6a94fed5..8560cfc460 100644 --- a/OutOfSchool/OutOfSchool.DataAccess/Repository/EntityRepositoryBase.cs +++ b/OutOfSchool/OutOfSchool.DataAccess/Repository/EntityRepositoryBase.cs @@ -77,6 +77,28 @@ public virtual async Task RunInTransaction(Func> operation) }); } + /// + public virtual async Task RunInTransaction(Func operation) + { + var executionStrategy = dbContext.Database.CreateExecutionStrategy(); + + await executionStrategy.ExecuteAsync( + async () => + { + await using IDbContextTransaction transaction = await dbContext.Database.BeginTransactionAsync(); + try + { + await operation().ConfigureAwait(false); + await transaction.CommitAsync().ConfigureAwait(false); + } + catch (Exception ex) + { + await transaction.RollbackAsync().ConfigureAwait(false); + throw; + } + }); + } + /// public virtual async Task Delete(TEntity entity) { diff --git a/OutOfSchool/OutOfSchool.DataAccess/Repository/IEntityRepository.cs b/OutOfSchool/OutOfSchool.DataAccess/Repository/IEntityRepository.cs index aa5bb06c94..020db88a0e 100644 --- a/OutOfSchool/OutOfSchool.DataAccess/Repository/IEntityRepository.cs +++ b/OutOfSchool/OutOfSchool.DataAccess/Repository/IEntityRepository.cs @@ -43,6 +43,13 @@ public interface IEntityRepositoryBase /// A representing the result of the asynchronous operation. Task RunInTransaction(Func> operation); + /// + /// Runs operation in transaction without result. + /// + /// Method that represents the operation. + /// A representing the result of the asynchronous operation. + Task RunInTransaction(Func operation); + /// /// Update information about element. /// diff --git a/OutOfSchool/OutOfSchool.WebApi/Services/ProviderService.cs b/OutOfSchool/OutOfSchool.WebApi/Services/ProviderService.cs index 46740a4955..b02c547e94 100644 --- a/OutOfSchool/OutOfSchool.WebApi/Services/ProviderService.cs +++ b/OutOfSchool/OutOfSchool.WebApi/Services/ProviderService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Data; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; @@ -304,7 +305,7 @@ public async Task Block(ProviderBlockDto providerBlockDto) provider.IsBlocked = providerBlockDto.IsBlocked; provider.BlockReason = providerBlockDto.IsBlocked ? providerBlockDto.BlockReason : null; - return await providerRepository.RunInTransaction(async () => + await providerRepository.RunInTransaction(async () => { await providerRepository.UnitOfWork.CompleteAsync().ConfigureAwait(false); @@ -319,8 +320,9 @@ public async Task Block(ProviderBlockDto providerBlockDto) } logger.LogInformation($"Provider(id) {providerBlockDto.Id} IsBlocked was changed to {provider.IsBlocked}"); - return providerBlockDto; }); + + return providerBlockDto; } public async Task UpdateLicenseStatus(ProviderLicenseStatusDto dto, string userId)