Browse Source

Merge pull request #7543 from olicooper/pr/repository-delete-updates

pull/7574/head
maliming 6 years ago
committed by GitHub
parent
commit
8cfc4d0762
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 17
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IRepository.cs
  2. 5
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs
  3. 5
      framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs
  4. 114
      framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs
  5. 17
      framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/SoftDelete_Tests.cs

17
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IRepository.cs

@ -20,8 +20,10 @@ namespace Volo.Abp.Domain.Repositories
{
/// <summary>
/// Get a single entity by the given <paramref name="predicate"/>.
/// It returns null if no entity with the given <paramref name="predicate"/>.
/// <para>
/// It returns null if there is no entity with the given <paramref name="predicate"/>.
/// It throws <see cref="InvalidOperationException"/> if there are multiple entities with the given <paramref name="predicate"/>.
/// </para>
/// </summary>
/// <param name="predicate">A condition to find the entity</param>
/// <param name="includeDetails">Set true to include all children of this entity</param>
@ -34,8 +36,10 @@ namespace Volo.Abp.Domain.Repositories
/// <summary>
/// Get a single entity by the given <paramref name="predicate"/>.
/// <para>
/// It throws <see cref="EntityNotFoundException"/> if there is no entity with the given <paramref name="predicate"/>.
/// It throws <see cref="InvalidOperationException"/> if there are multiple entities with the given <paramref name="predicate"/>.
/// </para>
/// </summary>
/// <param name="predicate">A condition to filter entities</param>
/// <param name="includeDetails">Set true to include all children of this entity</param>
@ -47,10 +51,11 @@ namespace Volo.Abp.Domain.Repositories
);
/// <summary>
/// Deletes many entities by function.
/// Notice that: All entities fits to given predicate are retrieved and deleted.
/// This may cause major performance problems if there are too many entities with
/// given predicate.
/// Deletes many entities by the given <paramref name="predicate"/>.
/// <para>
/// Please note: This may cause major performance problems if there are too many entities returned for a
/// given predicate and the database provider doesn't have a way to efficiently delete many entities.
/// </para>
/// </summary>
/// <param name="predicate">A condition to filter entities</param>
/// <param name="autoSave">
@ -69,4 +74,4 @@ namespace Volo.Abp.Domain.Repositories
where TEntity : class, IEntity<TKey>
{
}
}
}

5
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs

@ -289,10 +289,7 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore
.Where(predicate)
.ToListAsync(GetCancellationToken(cancellationToken));
foreach (var entity in entities)
{
dbSet.Remove(entity);
}
await DeleteManyAsync(entities, autoSave, cancellationToken);
if (autoSave)
{

5
framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs

@ -191,10 +191,7 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb
{
var entities = (await GetQueryableAsync()).Where(predicate).ToList();
foreach (var entity in entities)
{
await DeleteAsync(entity, autoSave, cancellationToken);
}
await DeleteManyAsync(entities, autoSave, cancellationToken);
}
public override async Task<TEntity> InsertAsync(

114
framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs

@ -71,16 +71,18 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
protected Task<TMongoDbContext> GetDbContextAsync(CancellationToken cancellationToken = default)
{
cancellationToken = GetCancellationToken(cancellationToken);
// Multi-tenancy unaware entities should always use the host connection string
if (!EntityHelper.IsMultiTenant<TEntity>())
{
using (CurrentTenant.Change(null))
{
return DbContextProvider.GetDbContextAsync(GetCancellationToken(cancellationToken));
return DbContextProvider.GetDbContextAsync(cancellationToken);
}
}
return DbContextProvider.GetDbContextAsync(GetCancellationToken(cancellationToken));
return DbContextProvider.GetDbContextAsync(cancellationToken);
}
protected IMongoDbContextProvider<TMongoDbContext> DbContextProvider { get; }
@ -107,9 +109,11 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
bool autoSave = false,
CancellationToken cancellationToken = default)
{
cancellationToken = GetCancellationToken(cancellationToken);
await ApplyAbpConceptsForAddedEntityAsync(entity);
var dbContext = await GetDbContextAsync(GetCancellationToken(cancellationToken));
var dbContext = await GetDbContextAsync(cancellationToken);
var collection = dbContext.Collection<TEntity>();
if (dbContext.SessionHandle != null)
@ -117,14 +121,14 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
await collection.InsertOneAsync(
dbContext.SessionHandle,
entity,
cancellationToken: GetCancellationToken(cancellationToken)
cancellationToken: cancellationToken
);
}
else
{
await collection.InsertOneAsync(
entity,
cancellationToken: GetCancellationToken(cancellationToken)
cancellationToken: cancellationToken
);
}
@ -133,6 +137,8 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
public override async Task InsertManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
{
cancellationToken = GetCancellationToken(cancellationToken);
var entityArray = entities.ToArray();
foreach (var entity in entityArray)
@ -140,7 +146,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
await ApplyAbpConceptsForAddedEntityAsync(entity);
}
var dbContext = await GetDbContextAsync(GetCancellationToken(cancellationToken));
var dbContext = await GetDbContextAsync(cancellationToken);
var collection = dbContext.Collection<TEntity>();
if (BulkOperationProvider != null)
@ -169,6 +175,8 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
bool autoSave = false,
CancellationToken cancellationToken = default)
{
cancellationToken = GetCancellationToken(cancellationToken);
SetModificationAuditProperties(entity);
if (entity is ISoftDelete softDeleteEntity && softDeleteEntity.IsDeleted)
@ -186,7 +194,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
var oldConcurrencyStamp = SetNewConcurrencyStamp(entity);
ReplaceOneResult result;
var dbContext = await GetDbContextAsync(GetCancellationToken(cancellationToken));
var dbContext = await GetDbContextAsync(cancellationToken);
var collection = dbContext.Collection<TEntity>();
if (dbContext.SessionHandle != null)
@ -195,7 +203,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
dbContext.SessionHandle,
CreateEntityFilter(entity, true, oldConcurrencyStamp),
entity,
cancellationToken: GetCancellationToken(cancellationToken)
cancellationToken: cancellationToken
);
}
else
@ -203,7 +211,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
result = await collection.ReplaceOneAsync(
CreateEntityFilter(entity, true, oldConcurrencyStamp),
entity,
cancellationToken: GetCancellationToken(cancellationToken)
cancellationToken: cancellationToken
);
}
@ -277,15 +285,18 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
bool autoSave = false,
CancellationToken cancellationToken = default)
{
await ApplyAbpConceptsForDeletedEntityAsync(entity);
var oldConcurrencyStamp = SetNewConcurrencyStamp(entity);
cancellationToken = GetCancellationToken(cancellationToken);
var dbContext = await GetDbContextAsync(GetCancellationToken(cancellationToken));
var dbContext = await GetDbContextAsync(cancellationToken);
var collection = dbContext.Collection<TEntity>();
if (entity is ISoftDelete softDeleteEntity && !IsHardDeleted(entity))
var oldConcurrencyStamp = SetNewConcurrencyStamp(entity);
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)) && !IsHardDeleted(entity))
{
softDeleteEntity.IsDeleted = true;
((ISoftDelete)entity).IsDeleted = true;
await ApplyAbpConceptsForDeletedEntityAsync(entity);
ReplaceOneResult result;
if (dbContext.SessionHandle != null)
@ -294,7 +305,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
dbContext.SessionHandle,
CreateEntityFilter(entity, true, oldConcurrencyStamp),
entity,
cancellationToken: GetCancellationToken(cancellationToken)
cancellationToken: cancellationToken
);
}
else
@ -302,7 +313,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
result = await collection.ReplaceOneAsync(
CreateEntityFilter(entity, true, oldConcurrencyStamp),
entity,
cancellationToken: GetCancellationToken(cancellationToken)
cancellationToken: cancellationToken
);
}
@ -313,6 +324,8 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
}
else
{
await ApplyAbpConceptsForDeletedEntityAsync(entity);
DeleteResult result;
if (dbContext.SessionHandle != null)
@ -320,14 +333,14 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
result = await collection.DeleteOneAsync(
dbContext.SessionHandle,
CreateEntityFilter(entity, true, oldConcurrencyStamp),
cancellationToken: GetCancellationToken(cancellationToken)
cancellationToken: cancellationToken
);
}
else
{
result = await collection.DeleteOneAsync(
CreateEntityFilter(entity, true, oldConcurrencyStamp),
GetCancellationToken(cancellationToken)
cancellationToken
);
}
@ -343,55 +356,55 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
bool autoSave = false,
CancellationToken cancellationToken = default)
{
var softDeletedEntities = new List<TEntity>();
cancellationToken = GetCancellationToken(cancellationToken);
var softDeletedEntities = new Dictionary<TEntity, string>();
var hardDeletedEntities = new List<TEntity>();
foreach (var entity in entities)
{
await ApplyAbpConceptsForDeletedEntityAsync(entity);
SetNewConcurrencyStamp(entity);
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)) && !IsHardDeleted(entity))
{
softDeletedEntities.Add(entity);
((ISoftDelete)entity).IsDeleted = true;
softDeletedEntities.Add(entity, SetNewConcurrencyStamp(entity));
}
else
{
hardDeletedEntities.Add(entity);
}
await ApplyAbpConceptsForDeletedEntityAsync(entity);
}
var dbContext = await GetDbContextAsync(GetCancellationToken(cancellationToken));
var dbContext = await GetDbContextAsync(cancellationToken);
var collection = dbContext.Collection<TEntity>();
if (BulkOperationProvider != null)
{
await BulkOperationProvider.DeleteManyAsync(this, entities.ToArray(), dbContext.SessionHandle, autoSave, cancellationToken);
await BulkOperationProvider.DeleteManyAsync(this, entities, dbContext.SessionHandle, autoSave, cancellationToken);
return;
}
if (softDeletedEntities.Count > 0)
{
UpdateResult updateResult;
var softDeleteEntitiesCount = softDeletedEntities.Count;
BulkWriteResult updateResult;
var replaceRequests = new List<WriteModel<TEntity>>(
softDeletedEntities.Select(entity => new ReplaceOneModel<TEntity>(
CreateEntityFilter(entity.Key, true, entity.Value), entity.Key))
);
if (dbContext.SessionHandle != null)
{
updateResult = await collection.UpdateManyAsync(
dbContext.SessionHandle,
CreateEntitiesFilter(softDeletedEntities),
Builders<TEntity>.Update.Set(x => ((ISoftDelete)x).IsDeleted, true)
);
updateResult = await collection.BulkWriteAsync(dbContext.SessionHandle, replaceRequests, cancellationToken: cancellationToken);
}
else
{
updateResult = await collection.UpdateManyAsync(
CreateEntitiesFilter(softDeletedEntities),
Builders<TEntity>.Update.Set(x => ((ISoftDelete)x).IsDeleted, true)
);
updateResult = await collection.BulkWriteAsync(replaceRequests, cancellationToken: cancellationToken);
}
if (updateResult.MatchedCount < softDeleteEntitiesCount)
if (updateResult.MatchedCount < softDeletedEntities.Count)
{
ThrowOptimisticConcurrencyException();
}
@ -406,14 +419,14 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
{
deleteResult = await collection.DeleteManyAsync(
dbContext.SessionHandle,
CreateEntitiesFilter(hardDeletedEntities)
);
CreateEntitiesFilter(hardDeletedEntities),
cancellationToken: cancellationToken);
}
else
{
deleteResult = await collection.DeleteManyAsync(
CreateEntitiesFilter(hardDeletedEntities)
);
CreateEntitiesFilter(hardDeletedEntities),
cancellationToken: cancellationToken);
}
if (deleteResult.DeletedCount < hardDeletedEntitiesCount)
@ -462,10 +475,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
.Where(predicate)
.ToListAsync(cancellationToken);
foreach (var entity in entities)
{
await DeleteAsync(entity, autoSave, cancellationToken);
}
await DeleteManyAsync(entities, autoSave, cancellationToken);
}
[Obsolete("Use GetQueryableAsync method.")]
@ -484,9 +494,11 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
bool includeDetails = true,
CancellationToken cancellationToken = default)
{
cancellationToken = GetCancellationToken(cancellationToken);
return await (await GetMongoQueryableAsync(cancellationToken))
.Where(predicate)
.SingleOrDefaultAsync(GetCancellationToken(cancellationToken));
.SingleOrDefaultAsync(cancellationToken);
}
[Obsolete("Use GetMongoQueryableAsync method.")]
@ -501,6 +513,8 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
public async Task<IMongoQueryable<TEntity>> GetMongoQueryableAsync(CancellationToken cancellationToken = default)
{
cancellationToken = GetCancellationToken(cancellationToken);
var dbContext = await GetDbContextAsync(cancellationToken);
var collection = dbContext.Collection<TEntity>();
@ -513,6 +527,8 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
public async Task<IAggregateFluent<TEntity>> GetAggregateAsync(CancellationToken cancellationToken = default)
{
cancellationToken = GetCancellationToken(cancellationToken);
var dbContext = await GetDbContextAsync(cancellationToken);
var collection = await GetCollectionAsync(cancellationToken);
@ -695,13 +711,13 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
[Obsolete("This method will be removed in future versions.")]
public IAsyncCursor<TEntity> ToCursor(CancellationToken cancellationToken = new CancellationToken())
{
return GetMongoQueryable().ToCursor(cancellationToken);
return GetMongoQueryable().ToCursor(GetCancellationToken(cancellationToken));
}
[Obsolete("This method will be removed in future versions.")]
public Task<IAsyncCursor<TEntity>> ToCursorAsync(CancellationToken cancellationToken = new CancellationToken())
{
return GetMongoQueryable().ToCursorAsync(cancellationToken);
return GetMongoQueryable().ToCursorAsync(GetCancellationToken(cancellationToken));
}
}
@ -724,7 +740,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
bool includeDetails = true,
CancellationToken cancellationToken = default)
{
var entity = await FindAsync(id, includeDetails, cancellationToken);
var entity = await FindAsync(id, includeDetails, GetCancellationToken(cancellationToken));
if (entity == null)
{

17
framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/SoftDelete_Tests.cs

@ -56,6 +56,23 @@ namespace Volo.Abp.TestApp.Testing
douglas.DeletionTime.ShouldNotBeNull();
}
}
[Fact]
public async Task Should_Cancel_Deletion_For_Soft_Delete_Many_Entities_ById()
{
await PersonRepository.DeleteManyAsync(new []{ TestDataBuilder.UserDouglasId });
var douglas = await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId);
douglas.ShouldBeNull();
using (DataFilter.Disable<ISoftDelete>())
{
douglas = await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId);
douglas.ShouldNotBeNull();
douglas.IsDeleted.ShouldBeTrue();
douglas.DeletionTime.ShouldNotBeNull();
}
}
[Fact]
public async Task Should_Handle_Deletion_On_Update_For_Soft_Delete_Entities()

Loading…
Cancel
Save