Skip to content

Commit

Permalink
Merge pull request #2807 from gterdem/pr/139-hardDelete
Browse files Browse the repository at this point in the history
Soft Delete enhancements #139
  • Loading branch information
hikalkan committed Feb 14, 2020
2 parents 43a11ed + 9392954 commit 2e20131
Show file tree
Hide file tree
Showing 14 changed files with 241 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
using System.Linq.Expressions;
using System.Reflection;
using JetBrains.Annotations;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Reflection;

namespace Volo.Abp.Domain.Entities
{
Expand All @@ -11,6 +13,7 @@ namespace Volo.Abp.Domain.Entities
/// </summary>
public static class EntityHelper
{

public static bool IsEntity([NotNull] Type type)
{
return typeof(IEntity).IsAssignableFrom(type);
Expand Down Expand Up @@ -82,10 +85,10 @@ public static Expression<Func<TEntity, bool>> CreateEqualityExpressionForId<TEnt
var lambdaBody = Expression.Equal(leftExpression, rightExpression);
return Expression.Lambda<Func<TEntity, bool>>(lambdaBody, lambdaParam);
}

public static void TrySetId<TKey>(
IEntity<TKey> entity,
Func<TKey> idFactory,
IEntity<TKey> entity,
Func<TKey> idFactory,
bool checkForDisableGuidGenerationAttribute = false)
{
//TODO: Can be optimized (by caching per entity type)?
Expand All @@ -109,5 +112,26 @@ public static void TrySetId<TKey>(

idProperty.SetValue(entity, idFactory());
}

public static object GetEntityId(object entity)
{
if (!IsEntity(entity.GetType()))
{
throw new AbpException(entity.GetType() + " is not an Entity !");
}

return ReflectionHelper.GetValueByPath(entity, entity.GetType(), "Id");
}
public static string GetHardDeleteKey(object entity, string tenantId)
{
//if (entity is IMultiTenant) // IsMultiTenantEntity
if (typeof(IMultiTenant).IsAssignableFrom(entity.GetType()))
{
var tenantIdString = !string.IsNullOrEmpty(tenantId) ? tenantId : "null";
return entity.GetType().FullName + ";TenantId=" + tenantIdString + ";Id=" + GetEntityId(entity);
}

return entity.GetType().FullName + ";Id=" + GetEntityId(entity);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@
using Volo.Abp.Data;
using Volo.Abp.Domain.Entities;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Uow;

namespace Volo.Abp.Domain.Repositories
{
public abstract class RepositoryBase<TEntity> : BasicRepositoryBase<TEntity>, IRepository<TEntity>
public abstract class RepositoryBase<TEntity> : BasicRepositoryBase<TEntity>, IRepository<TEntity>, IUnitOfWorkManagerAccessor
where TEntity : class, IEntity
{
public IDataFilter DataFilter { get; set; }

public ICurrentTenant CurrentTenant { get; set; }
public IUnitOfWorkManager UnitOfWorkManager { get; set; }

public virtual Type ElementType => GetQueryable().ElementType;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Entities;
using Volo.Abp.DynamicProxy;
using Volo.Abp.Uow;

namespace Volo.Abp.Domain.Repositories
{
Expand Down Expand Up @@ -41,5 +43,32 @@ public static async Task EnsurePropertyLoadedAsync<TEntity, TKey, TProperty>(
await repo.EnsurePropertyLoadedAsync(entity, propertyExpression, cancellationToken);
}
}

public static async Task HardDeleteAsync<TEntity, TPrimaryKey>(this IRepository<TEntity, TPrimaryKey> repository, TEntity entity)
where TEntity : class, IEntity<TPrimaryKey>, ISoftDelete
{
var repo = ProxyHelper.UnProxy(repository) as IRepository<TEntity, TPrimaryKey>;
if (repo != null)
{
var uow = ((IUnitOfWorkManagerAccessor)repo).UnitOfWorkManager;
var baseRepository = ((RepositoryBase<TEntity>)repo);

var items = ((IUnitOfWorkManagerAccessor)repo).UnitOfWorkManager.Current.Items;
var hardDeleteEntities = items.GetOrAdd(UnitOfWorkExtensionDataTypes.HardDelete, () => new HashSet<string>()) as HashSet<string>;

var hardDeleteKey = EntityHelper.GetHardDeleteKey(entity, baseRepository.CurrentTenant?.Id?.ToString());
hardDeleteEntities.Add(hardDeleteKey);

await repo.DeleteAsync(entity);
}
}
public static async Task HardDeleteAsync<TEntity, TPrimaryKey>(this IRepository<TEntity, TPrimaryKey> repository, Expression<Func<TEntity, bool>> predicate)
where TEntity : class, IEntity<TPrimaryKey>, ISoftDelete
{
foreach (var entity in repository.Where(predicate).ToList())
{
await repository.HardDeleteAsync(entity);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Volo.Abp.Domain.Repositories
{
public class UnitOfWorkExtensionDataTypes
{
public static string HardDelete { get; } = "HardDelete";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.EntityFrameworkCore.EntityHistory;
using Volo.Abp.EntityFrameworkCore.Modeling;
using Volo.Abp.EntityFrameworkCore.ValueConverters;
using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Reflection;
using Volo.Abp.Timing;
using Volo.Abp.Uow;

namespace Volo.Abp.EntityFrameworkCore
{
Expand All @@ -48,6 +50,7 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IEfCoreDbContext, IT
public IEntityHistoryHelper EntityHistoryHelper { get; set; }

public IAuditingManager AuditingManager { get; set; }
public IUnitOfWorkManager UnitOfWorkManager { get; set; }

public IClock Clock { get; set; }

Expand Down Expand Up @@ -102,7 +105,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
.Invoke(this, new object[] { modelBuilder, entityType });
}
}

public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default)
{
try
Expand Down Expand Up @@ -196,12 +199,39 @@ protected virtual void ApplyAbpConceptsForModifiedEntity(EntityEntry entry, Enti

protected virtual void ApplyAbpConceptsForDeletedEntity(EntityEntry entry, EntityChangeReport changeReport)
{
if (IsHardDeleteEntity(entry))
{
changeReport.ChangedEntities.Add(new EntityChangeEntry(entry.Entity, EntityChangeType.Deleted));
return;
}
CancelDeletionForSoftDelete(entry);
UpdateConcurrencyStamp(entry);
SetDeletionAuditProperties(entry);
changeReport.ChangedEntities.Add(new EntityChangeEntry(entry.Entity, EntityChangeType.Deleted));
}

protected virtual bool IsHardDeleteEntity(EntityEntry entry)
{
if (UnitOfWorkManager?.Current?.Items == null)
{
return false;
}

if (!UnitOfWorkManager.Current.Items.ContainsKey(UnitOfWorkExtensionDataTypes.HardDelete))
{
return false;
}

var hardDeleteItems = UnitOfWorkManager.Current.Items[UnitOfWorkExtensionDataTypes.HardDelete];
if (!(hardDeleteItems is HashSet<string> objects))
{
return false;
}
string hardDeleteKey = EntityHelper.GetHardDeleteKey(entry.Entity, CurrentTenantId?.ToString());

return objects.Contains(hardDeleteKey);
}

protected virtual void AddDomainEvents(EntityChangeReport changeReport, object entityAsObj)
{
var generatesDomainEventsEntity = entityAsObj as IGeneratesDomainEvents;
Expand Down Expand Up @@ -382,7 +412,7 @@ protected virtual void ConfigureValueGenerated<TEntity>(ModelBuilder modelBuilde
return;
}

var idPropertyBuilder = modelBuilder.Entity<TEntity>().Property(x => ((IEntity<Guid>) x).Id);
var idPropertyBuilder = modelBuilder.Entity<TEntity>().Property(x => ((IEntity<Guid>)x).Id);
if (idPropertyBuilder.Metadata.PropertyInfo.IsDefined(typeof(DatabaseGeneratedAttribute), true))
{
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public override async Task DeleteAsync(
await ApplyAbpConceptsForDeletedEntityAsync(entity);
var oldConcurrencyStamp = SetNewConcurrencyStamp(entity);

if (entity is ISoftDelete softDeleteEntity)
if (entity is ISoftDelete softDeleteEntity && !IsHardDeleteEntity(entity))
{
softDeleteEntity.IsDeleted = true;
var result = await Collection.ReplaceOneAsync(
Expand Down Expand Up @@ -175,6 +175,27 @@ public virtual IMongoQueryable<TEntity> GetMongoQueryable()
Collection.AsQueryable()
);
}
protected virtual bool IsHardDeleteEntity(TEntity entry)
{
if (UnitOfWorkManager?.Current?.Items == null)
{
return false;
}

if (!UnitOfWorkManager.Current.Items.ContainsKey(UnitOfWorkExtensionDataTypes.HardDelete))
{
return false;
}

var hardDeleteItems = UnitOfWorkManager.Current.Items[UnitOfWorkExtensionDataTypes.HardDelete];
if (!(hardDeleteItems is HashSet<string> objects))
{
return false;
}
string hardDeleteKey = EntityHelper.GetHardDeleteKey(entry, CurrentTenant?.Id.ToString());

return objects.Contains(hardDeleteKey);
}

protected virtual FilterDefinition<TEntity> CreateEntityFilter(TEntity entity, bool withConcurrencyStamp = false, string concurrencyStamp = null)
{
Expand Down
3 changes: 3 additions & 0 deletions framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
Expand Down Expand Up @@ -26,6 +27,8 @@ internal class ChildUnitOfWork : IUnitOfWork

public IServiceProvider ServiceProvider => _parent.ServiceProvider;

public Dictionary<string, object> Items => _parent.Items;

private readonly IUnitOfWork _parent;

public ChildUnitOfWork([NotNull] IUnitOfWork parent)
Expand Down
2 changes: 2 additions & 0 deletions framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
Expand All @@ -8,6 +9,7 @@ namespace Volo.Abp.Uow
public interface IUnitOfWork : IDatabaseApiContainer, ITransactionApiContainer, IDisposable
{
Guid Id { get; }
Dictionary<string, object> Items { get; }

//TODO: Switch to OnFailed (sync) and OnDisposed (sync) methods to be compatible with OnCompleted
event EventHandler<UnitOfWorkFailedEventArgs> Failed;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Volo.Abp.Uow
{
public interface IUnitOfWorkManagerAccessor
{
IUnitOfWorkManager UnitOfWorkManager { get; }
}
}
8 changes: 8 additions & 0 deletions framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public class UnitOfWork : IUnitOfWork, ITransientDependency

public IServiceProvider ServiceProvider { get; }

public Dictionary<string, object> Items { get; }

private readonly Dictionary<string, IDatabaseApi> _databaseApis;
private readonly Dictionary<string, ITransactionApi> _transactionApis;
private readonly AbpUnitOfWorkDefaultOptions _defaultOptions;
Expand All @@ -46,6 +48,7 @@ public UnitOfWork(IServiceProvider serviceProvider, IOptions<AbpUnitOfWorkDefaul

_databaseApis = new Dictionary<string, IDatabaseApi>();
_transactionApis = new Dictionary<string, ITransactionApi>();
Items = new Dictionary<string, object>();
}

public virtual void Initialize(AbpUnitOfWorkOptions options)
Expand Down Expand Up @@ -317,5 +320,10 @@ public override string ToString()
{
return $"[UnitOfWork {Id}]";
}

public Dictionary<string, object> GetHardDeleteItems()
{
return Items;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Volo.Abp.TestApp.Testing;

namespace Volo.Abp.EntityFrameworkCore.DataFiltering
{
public class HardDelete_Tests : HardDelete_Tests<AbpEntityFrameworkCoreTestModule>
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
using Volo.Abp.TestApp.Testing;

namespace Volo.Abp.MongoDB.DataFiltering
{
public class HardDelete_Tests : HardDelete_Tests<AbpMongoDbTestModule>
{
}
}
11 changes: 6 additions & 5 deletions framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/Phone.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
namespace Volo.Abp.TestApp.Domain
{
[Table("AppPhones")]
public class Phone : Entity
public class Phone : Entity<Guid>
{
public virtual Guid PersonId { get; set; }

Expand All @@ -17,19 +17,20 @@ public class Phone : Entity

private Phone()
{

}

public Phone(Guid personId, string number, PhoneType type = PhoneType.Mobile)
{
Id = Guid.NewGuid();
PersonId = personId;
Number = number;
Type = type;
}

public override object[] GetKeys()
{
return new object[] {PersonId, Number};
return new object[] { PersonId, Number };
}
}

Expand All @@ -45,7 +46,7 @@ public class Order : AggregateRoot<Guid>

protected Order()
{

}

public Order(Guid id, string referenceNo)
Expand Down Expand Up @@ -104,7 +105,7 @@ internal void ChangeCount(int newCount)

public override object[] GetKeys()
{
return new object[] {OrderId, ProductId};
return new object[] { OrderId, ProductId };
}
}
}
Loading

0 comments on commit 2e20131

Please sign in to comment.