From 70a1bfe0c4b3ebd08c93280027a475f1cee04110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 10 Mar 2018 21:31:02 +0300 Subject: [PATCH] #230 Add autosave option to update and delete methods of the repository. --- .../Abp/Data}/AbpDbConcurrencyException.cs | 2 +- .../Repositories/BasicRepositoryBase.cs | 12 ++-- .../Domain/Repositories/IBasicRepository.cs | 46 +++++++++++---- .../Abp/Domain/Repositories/RepositoryBase.cs | 4 +- .../EntityFrameworkCore/EfCoreRepository.cs | 58 ++++++++++++++++--- .../Volo/Abp/Identity/IdentityRoleStore.cs | 28 ++------- .../Volo/Abp/Identity/IdentityUserStore.cs | 25 +------- .../MemoryDb/MemoryDbRepository.cs | 8 +-- .../Repositories/MongoDB/MongoDbRepository.cs | 12 ++-- .../RepositoryRegistration_Tests.cs | 8 +-- 10 files changed, 115 insertions(+), 88 deletions(-) rename src/{Volo.Abp.Ddd/Volo/Abp/Uow => Volo.Abp.Data/Volo/Abp/Data}/AbpDbConcurrencyException.cs (97%) diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Uow/AbpDbConcurrencyException.cs b/src/Volo.Abp.Data/Volo/Abp/Data/AbpDbConcurrencyException.cs similarity index 97% rename from src/Volo.Abp.Ddd/Volo/Abp/Uow/AbpDbConcurrencyException.cs rename to src/Volo.Abp.Data/Volo/Abp/Data/AbpDbConcurrencyException.cs index 0c026c4361..931cf3fed0 100644 --- a/src/Volo.Abp.Ddd/Volo/Abp/Uow/AbpDbConcurrencyException.cs +++ b/src/Volo.Abp.Data/Volo/Abp/Data/AbpDbConcurrencyException.cs @@ -1,6 +1,6 @@ using System; -namespace Volo.Abp.Uow +namespace Volo.Abp.Data { public class AbpDbConcurrencyException : AbpException { diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Domain/Repositories/BasicRepositoryBase.cs b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Repositories/BasicRepositoryBase.cs index 5870aeef06..a23d3cb011 100644 --- a/src/Volo.Abp.Ddd/Volo/Abp/Domain/Repositories/BasicRepositoryBase.cs +++ b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Repositories/BasicRepositoryBase.cs @@ -22,16 +22,16 @@ namespace Volo.Abp.Domain.Repositories return Task.FromResult(Insert(entity, autoSave)); } - public abstract TEntity Update(TEntity entity); + public abstract TEntity Update(TEntity entity, bool autoSave = false); - public virtual Task UpdateAsync(TEntity entity, CancellationToken cancellationToken = default) + public virtual Task UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { return Task.FromResult(Update(entity)); } - public abstract void Delete(TEntity entity); + public abstract void Delete(TEntity entity, bool autoSave = false); - public virtual Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default) + public virtual Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { Delete(entity); return Task.CompletedTask; @@ -70,7 +70,7 @@ namespace Volo.Abp.Domain.Repositories return Task.FromResult(Find(id)); } - public virtual void Delete(TKey id) + public virtual void Delete(TKey id, bool autoSave = false) { var entity = Find(id); if (entity == null) @@ -81,7 +81,7 @@ namespace Volo.Abp.Domain.Repositories Delete(entity); } - public virtual Task DeleteAsync(TKey id, CancellationToken cancellationToken = default) + public virtual Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default) { Delete(id); return Task.CompletedTask; diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Domain/Repositories/IBasicRepository.cs b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Repositories/IBasicRepository.cs index 91984a1848..daaa19176c 100644 --- a/src/Volo.Abp.Ddd/Volo/Abp/Domain/Repositories/IBasicRepository.cs +++ b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Repositories/IBasicRepository.cs @@ -13,8 +13,8 @@ namespace Volo.Abp.Domain.Repositories /// /// Inserted entity /// - /// Set true to automatically save changes to database. - /// This can be used to set database generated Id of an entity for some ORMs (like Entity Framework). + /// Set true to automatically save entity to database. + /// This is useful for ORMs / database APIs those only saves changes with an explicit method call. /// [NotNull] TEntity Insert([NotNull] TEntity entity, bool autoSave = false); @@ -24,7 +24,7 @@ namespace Volo.Abp.Domain.Repositories /// /// /// Set true to automatically save changes to database. - /// This can be used to set database generated Id of an entity for some ORMs (like Entity Framework). + /// This is useful for ORMs / database APIs those only saves changes with an explicit method call. /// /// A to observe while waiting for the task to complete. /// Inserted entity @@ -35,29 +35,45 @@ namespace Volo.Abp.Domain.Repositories /// Updates an existing entity. /// /// Entity + /// + /// Set true to automatically save changes to database. + /// This is useful for ORMs / database APIs those only saves changes with an explicit method call. + /// [NotNull] - TEntity Update([NotNull] TEntity entity); + TEntity Update([NotNull] TEntity entity, bool autoSave = false); /// /// Updates an existing entity. /// + /// + /// Set true to automatically save changes to database. + /// This is useful for ORMs / database APIs those only saves changes with an explicit method call. + /// /// A to observe while waiting for the task to complete. /// Entity [NotNull] - Task UpdateAsync([NotNull] TEntity entity, CancellationToken cancellationToken = default); + Task UpdateAsync([NotNull] TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default); /// /// Deletes an entity. /// /// Entity to be deleted - void Delete([NotNull] TEntity entity); //TODO: Return true if deleted + /// + /// Set true to automatically save changes to database. + /// This is useful for ORMs / database APIs those only saves changes with an explicit method call. + /// + void Delete([NotNull] TEntity entity, bool autoSave = false); //TODO: Return true if deleted /// /// Deletes an entity. /// - /// A to observe while waiting for the task to complete. /// Entity to be deleted - Task DeleteAsync([NotNull] TEntity entity, CancellationToken cancellationToken = default); //TODO: Return true if deleted + /// + /// Set true to automatically save changes to database. + /// This is useful for ORMs / database APIs those only saves changes with an explicit method call. + /// + /// A to observe while waiting for the task to complete. + Task DeleteAsync([NotNull] TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default); //TODO: Return true if deleted } public interface IBasicRepository : IBasicRepository @@ -102,13 +118,21 @@ namespace Volo.Abp.Domain.Repositories /// Deletes an entity by primary key. /// /// Primary key of the entity - void Delete(TKey id); //TODO: Return true if deleted + /// + /// Set true to automatically save changes to database. + /// This is useful for ORMs / database APIs those only saves changes with an explicit method call. + /// + void Delete(TKey id, bool autoSave = false); //TODO: Return true if deleted /// /// Deletes an entity by primary key. /// - /// A to observe while waiting for the task to complete. /// Primary key of the entity - Task DeleteAsync(TKey id, CancellationToken cancellationToken = default); //TODO: Return true if deleted + /// + /// Set true to automatically save changes to database. + /// This is useful for ORMs / database APIs those only saves changes with an explicit method call. + /// + /// A to observe while waiting for the task to complete. + Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default); //TODO: Return true if deleted } } diff --git a/src/Volo.Abp.Ddd/Volo/Abp/Domain/Repositories/RepositoryBase.cs b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Repositories/RepositoryBase.cs index ba901e649c..a3c8d52989 100644 --- a/src/Volo.Abp.Ddd/Volo/Abp/Domain/Repositories/RepositoryBase.cs +++ b/src/Volo.Abp.Ddd/Volo/Abp/Domain/Repositories/RepositoryBase.cs @@ -97,7 +97,7 @@ namespace Volo.Abp.Domain.Repositories return Task.FromResult(Find(id)); } - public virtual void Delete(TKey id) + public virtual void Delete(TKey id, bool autoSave = false) { var entity = Find(id); if (entity == null) @@ -108,7 +108,7 @@ namespace Volo.Abp.Domain.Repositories Delete(entity); } - public virtual Task DeleteAsync(TKey id, CancellationToken cancellationToken = default) + public virtual Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default) { Delete(id); return Task.CompletedTask; diff --git a/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs b/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs index a75d5f4cf8..d24124687f 100644 --- a/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs +++ b/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs @@ -51,15 +51,52 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore return savedEntity; } - public override TEntity Update(TEntity entity) + public override TEntity Update(TEntity entity, bool autoSave = false) { DbContext.Attach(entity); - return DbContext.Update(entity).Entity; + + var updatedEntity = DbContext.Update(entity).Entity; + + if (autoSave) + { + DbContext.SaveChanges(); + } + + return updatedEntity; + } + + public override async Task UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) + { + DbContext.Attach(entity); + + var updatedEntity = DbContext.Update(entity).Entity; + + if (autoSave) + { + await DbContext.SaveChangesAsync(cancellationToken); + } + + return updatedEntity; } - public override void Delete(TEntity entity) + public override void Delete(TEntity entity, bool autoSave = false) { DbSet.Remove(entity); + + if (autoSave) + { + DbContext.SaveChanges(); + } + } + + public override async Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) + { + DbSet.Remove(entity); + + if (autoSave) + { + await DbContext.SaveChangesAsync(cancellationToken); + } } protected override IQueryable GetQueryable() @@ -142,7 +179,7 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore return await DbSet.FindAsync(new object[] { id }, GetCancellationToken(cancellationToken)); } - public virtual void Delete(TKey id) + public virtual void Delete(TKey id, bool autoSave = false) { var entity = Find(id); if (entity == null) @@ -150,13 +187,18 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore return; } - Delete(entity); + Delete(entity, autoSave); } - public virtual Task DeleteAsync(TKey id, CancellationToken cancellationToken = default) + public virtual async Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default) { - Delete(id); - return Task.CompletedTask; + var entity = await FindAsync(id, cancellationToken); + if (entity == null) + { + return; + } + + await DeleteAsync(entity, autoSave, cancellationToken); } } } diff --git a/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleStore.cs b/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleStore.cs index 1dab2df56c..5a2781cd6e 100644 --- a/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleStore.cs +++ b/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleStore.cs @@ -7,10 +7,10 @@ using System.Threading.Tasks; using JetBrains.Annotations; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Logging; +using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Repositories; using Volo.Abp.Guids; -using Volo.Abp.Uow; namespace Volo.Abp.Identity { @@ -23,7 +23,6 @@ namespace Volo.Abp.Identity ITransientDependency { private readonly IIdentityRoleRepository _roleRepository; - private readonly IUnitOfWorkManager _unitOfWorkManager; private readonly ILogger _logger; private readonly IGuidGenerator _guidGenerator; @@ -31,13 +30,11 @@ namespace Volo.Abp.Identity /// Constructs a new instance of . /// public IdentityRoleStore( - IUnitOfWorkManager unitOfWorkManager, IIdentityRoleRepository roleRepository, ILogger logger, IGuidGenerator guidGenerator, IdentityErrorDescriber describer = null) { - _unitOfWorkManager = unitOfWorkManager; _roleRepository = roleRepository; _logger = logger; _guidGenerator = guidGenerator; @@ -58,19 +55,6 @@ namespace Volo.Abp.Identity /// public bool AutoSaveChanges { get; set; } = true; - /// Saves the current store. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation. - protected Task SaveChanges(CancellationToken cancellationToken) - { - if (!AutoSaveChanges || _unitOfWorkManager.Current == null) - { - return Task.CompletedTask; - } - - return _unitOfWorkManager.Current.SaveChangesAsync(cancellationToken); - } - /// /// Creates a new role in a store as an asynchronous operation. /// @@ -83,8 +67,7 @@ namespace Volo.Abp.Identity Check.NotNull(role, nameof(role)); - await _roleRepository.InsertAsync(role, cancellationToken: cancellationToken); - await SaveChanges(cancellationToken); + await _roleRepository.InsertAsync(role, AutoSaveChanges, cancellationToken); return IdentityResult.Success; } @@ -101,11 +84,9 @@ namespace Volo.Abp.Identity Check.NotNull(role, nameof(role)); - await _roleRepository.UpdateAsync(role, cancellationToken); - try { - await SaveChanges(cancellationToken); + await _roleRepository.UpdateAsync(role, AutoSaveChanges, cancellationToken); } catch (AbpDbConcurrencyException ex) { @@ -130,8 +111,7 @@ namespace Volo.Abp.Identity try { - await _roleRepository.DeleteAsync(role, cancellationToken); - await SaveChanges(cancellationToken); + await _roleRepository.DeleteAsync(role, AutoSaveChanges, cancellationToken); } catch (AbpDbConcurrencyException ex) { diff --git a/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs b/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs index c5782269ac..c7d96bb9e8 100644 --- a/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs +++ b/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs @@ -8,10 +8,10 @@ using System.Threading.Tasks; using JetBrains.Annotations; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Logging; +using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Repositories; using Volo.Abp.Guids; -using Volo.Abp.Uow; namespace Volo.Abp.Identity { @@ -48,17 +48,14 @@ namespace Volo.Abp.Identity private readonly IGuidGenerator _guidGenerator; private readonly ILogger _logger; private readonly IIdentityUserRepository _userRepository; - private readonly IUnitOfWorkManager _unitOfWorkManager; public IdentityUserStore( - IUnitOfWorkManager unitOfWorkManager, IIdentityUserRepository userRepository, IIdentityRoleRepository roleRepository, IGuidGenerator guidGenerator, ILogger logger, IdentityErrorDescriber describer = null) { - _unitOfWorkManager = unitOfWorkManager; _userRepository = userRepository; _roleRepository = roleRepository; _guidGenerator = guidGenerator; @@ -67,19 +64,6 @@ namespace Volo.Abp.Identity ErrorDescriber = describer ?? new IdentityErrorDescriber(); } - /// Saves the current store. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation. - protected Task SaveChanges(CancellationToken cancellationToken) - { - if (!AutoSaveChanges || _unitOfWorkManager.Current == null) - { - return Task.CompletedTask; - } - - return _unitOfWorkManager.Current.SaveChangesAsync(cancellationToken); - } - /// /// Gets the user identifier for the specified . /// @@ -174,7 +158,6 @@ namespace Volo.Abp.Identity Check.NotNull(user, nameof(user)); await _userRepository.InsertAsync(user, AutoSaveChanges, cancellationToken); - await SaveChanges(cancellationToken); return IdentityResult.Success; } @@ -193,8 +176,7 @@ namespace Volo.Abp.Identity try { - await _userRepository.UpdateAsync(user, cancellationToken); - await SaveChanges(cancellationToken); + await _userRepository.UpdateAsync(user, AutoSaveChanges, cancellationToken); } catch (AbpDbConcurrencyException ex) { @@ -219,8 +201,7 @@ namespace Volo.Abp.Identity try { - await _userRepository.DeleteAsync(user, cancellationToken); - await SaveChanges(cancellationToken); + await _userRepository.DeleteAsync(user, AutoSaveChanges, cancellationToken); } catch (AbpDbConcurrencyException ex) { diff --git a/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs b/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs index 491338acca..171e574f87 100644 --- a/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs +++ b/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs @@ -29,12 +29,12 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb return entity; } - public override TEntity Update(TEntity entity) + public override TEntity Update(TEntity entity, bool autoSave = false) { return entity; } - public override void Delete(TEntity entity) + public override void Delete(TEntity entity, bool autoSave = false) { Collection.Remove(entity); } @@ -98,7 +98,7 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb return Task.FromResult(Find(id)); } - public virtual void Delete(TKey id) + public virtual void Delete(TKey id, bool autoSave = false) { var entity = Find(id); if (entity == null) @@ -109,7 +109,7 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb Delete(entity); } - public virtual Task DeleteAsync(TKey id, CancellationToken cancellationToken = default) + public virtual Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default) { Delete(id); return Task.CompletedTask; diff --git a/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs b/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs index 58471b6d97..79f1f19c5f 100644 --- a/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs +++ b/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs @@ -38,24 +38,24 @@ namespace Volo.Abp.Domain.Repositories.MongoDB return entity; } - public override TEntity Update(TEntity entity) + public override TEntity Update(TEntity entity, bool autoSave = false) { Collection.ReplaceOne(CreateEntityFilter(entity), entity); return entity; } - public override async Task UpdateAsync(TEntity entity, CancellationToken cancellationToken = default) + public override async Task UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { await Collection.ReplaceOneAsync(CreateEntityFilter(entity), entity, cancellationToken: cancellationToken); return entity; } - public override void Delete(TEntity entity) + public override void Delete(TEntity entity, bool autoSave = false) { Collection.DeleteOne(CreateEntityFilter(entity)); } - public override async Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default) + public override async Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { await Collection.DeleteOneAsync(CreateEntityFilter(entity), cancellationToken); } @@ -115,12 +115,12 @@ namespace Volo.Abp.Domain.Repositories.MongoDB return entity; } - public virtual void Delete(TKey id) + public virtual void Delete(TKey id, bool autoSave = false) { Collection.DeleteOne(CreateEntityFilter(id)); } - public virtual Task DeleteAsync(TKey id, CancellationToken cancellationToken = default) + public virtual Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default) { return Collection.DeleteOneAsync(CreateEntityFilter(id), cancellationToken); } diff --git a/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs b/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs index 9fc5e2cff8..75924ab110 100644 --- a/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs +++ b/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs @@ -158,12 +158,12 @@ namespace Volo.Abp.Domain.Repositories throw new NotImplementedException(); } - public override TEntity Update(TEntity entity) + public override TEntity Update(TEntity entity, bool autoSave = false) { throw new NotImplementedException(); } - public override void Delete(TEntity entity) + public override void Delete(TEntity entity, bool autoSave = false) { throw new NotImplementedException(); } @@ -192,12 +192,12 @@ namespace Volo.Abp.Domain.Repositories throw new NotImplementedException(); } - public void Delete(TKey id) + public void Delete(TKey id, bool autoSave = false) { throw new NotImplementedException(); } - public Task DeleteAsync(TKey id, CancellationToken cancellationToken = default) + public Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default) { throw new NotImplementedException(); }