mirror of https://github.com/abpframework/abp.git
9 changed files with 248 additions and 29 deletions
@ -0,0 +1,103 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Concurrent; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.Data |
||||
|
{ |
||||
|
public class DataFilter : IDataFilter, ISingletonDependency |
||||
|
{ |
||||
|
private readonly ConcurrentDictionary<Type, object> _filters; |
||||
|
|
||||
|
private readonly IServiceProvider _serviceProvider; |
||||
|
|
||||
|
public DataFilter(IServiceProvider serviceProvider) |
||||
|
{ |
||||
|
_serviceProvider = serviceProvider; |
||||
|
_filters = new ConcurrentDictionary<Type, object>(); |
||||
|
} |
||||
|
|
||||
|
public IDisposable Enable<TFilter>() |
||||
|
where TFilter : class |
||||
|
{ |
||||
|
return GetFilter<TFilter>().Enable(); |
||||
|
} |
||||
|
|
||||
|
public IDisposable Disable<TFilter>() |
||||
|
where TFilter : class |
||||
|
{ |
||||
|
return GetFilter<TFilter>().Disable(); |
||||
|
} |
||||
|
|
||||
|
public bool IsEnabled<TFilter>() |
||||
|
where TFilter : class |
||||
|
{ |
||||
|
return GetFilter<TFilter>().IsEnabled; |
||||
|
} |
||||
|
|
||||
|
private IDataFilter<TFilter> GetFilter<TFilter>() |
||||
|
where TFilter : class |
||||
|
{ |
||||
|
return _filters.GetOrAdd( |
||||
|
typeof(TFilter), |
||||
|
() => _serviceProvider.GetRequiredService<IDataFilter<TFilter>>() |
||||
|
) as IDataFilter<TFilter>; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class DataFilter<TFilter> : IDataFilter<TFilter> |
||||
|
where TFilter : class |
||||
|
{ |
||||
|
public bool IsEnabled |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
EnsureInitialized(); |
||||
|
return _filter.Value.IsEnabled; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private readonly AsyncLocal<DataFilterItem> _filter; |
||||
|
|
||||
|
public DataFilter() |
||||
|
{ |
||||
|
_filter = new AsyncLocal<DataFilterItem>(); |
||||
|
} |
||||
|
|
||||
|
public IDisposable Enable() |
||||
|
{ |
||||
|
if (IsEnabled) |
||||
|
{ |
||||
|
return NullDisposable.Instance; |
||||
|
} |
||||
|
|
||||
|
_filter.Value.IsEnabled = true; |
||||
|
|
||||
|
return new DisposeAction(() => Disable()); |
||||
|
} |
||||
|
|
||||
|
public IDisposable Disable() |
||||
|
{ |
||||
|
if (!IsEnabled) |
||||
|
{ |
||||
|
return NullDisposable.Instance; |
||||
|
} |
||||
|
|
||||
|
_filter.Value.IsEnabled = false; |
||||
|
|
||||
|
return new DisposeAction(() => Enable()); |
||||
|
} |
||||
|
|
||||
|
private void EnsureInitialized() |
||||
|
{ |
||||
|
if (_filter.Value != null) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
_filter.Value = new DataFilterItem { IsEnabled = true }; //TODO: Get from default setting!
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Abp.Data |
||||
|
{ |
||||
|
internal class DataFilterItem |
||||
|
{ |
||||
|
public bool IsEnabled { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Volo.Abp.Data |
||||
|
{ |
||||
|
public interface IDataFilter<TFilter> |
||||
|
where TFilter : class |
||||
|
{ |
||||
|
IDisposable Enable(); |
||||
|
|
||||
|
IDisposable Disable(); |
||||
|
|
||||
|
bool IsEnabled { get; } |
||||
|
} |
||||
|
|
||||
|
public interface IDataFilter |
||||
|
{ |
||||
|
IDisposable Enable<TFilter>() |
||||
|
where TFilter : class; |
||||
|
|
||||
|
IDisposable Disable<TFilter>() |
||||
|
where TFilter : class; |
||||
|
|
||||
|
bool IsEnabled<TFilter>() |
||||
|
where TFilter : class; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Volo.Abp |
||||
|
{ |
||||
|
internal sealed class NullDisposable : IDisposable |
||||
|
{ |
||||
|
public static NullDisposable Instance { get; } = new NullDisposable(); |
||||
|
|
||||
|
private NullDisposable() |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,64 @@ |
|||||
|
using System.Linq; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.Data; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
using Volo.Abp.TestApp.Domain; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.EntityFrameworkCore.DataFiltering |
||||
|
{ |
||||
|
public class SoftDelete_Filter_Tests : EntityFrameworkCoreTestBase |
||||
|
{ |
||||
|
private readonly IRepository<Person> _personRepository; |
||||
|
private readonly IDataFilter _dataFilter; |
||||
|
|
||||
|
public SoftDelete_Filter_Tests() |
||||
|
{ |
||||
|
_personRepository = GetRequiredService<IRepository<Person>>(); |
||||
|
_dataFilter = GetRequiredService<IDataFilter>(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_Not_Get_Deleted_Entities_By_Default() |
||||
|
{ |
||||
|
var people = _personRepository.GetList(); |
||||
|
people.Count.ShouldBe(1); |
||||
|
people.Any(p => p.Name == "Douglas").ShouldBeTrue(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_Get_Deleted_Entities_When_Filter_Is_Disabled() |
||||
|
{ |
||||
|
//Soft delete is enabled by default
|
||||
|
var people = _personRepository.GetList(); |
||||
|
people.Any(p => !p.IsDeleted).ShouldBeTrue(); |
||||
|
people.Any(p => p.IsDeleted).ShouldBeFalse(); |
||||
|
|
||||
|
using (_dataFilter.Disable<ISoftDelete>()) |
||||
|
{ |
||||
|
//Soft delete is disabled
|
||||
|
people = _personRepository.GetList(); |
||||
|
people.Any(p => !p.IsDeleted).ShouldBeTrue(); |
||||
|
people.Any(p => p.IsDeleted).ShouldBeTrue(); |
||||
|
|
||||
|
using (_dataFilter.Enable<ISoftDelete>()) |
||||
|
{ |
||||
|
//Soft delete is enabled again
|
||||
|
people = _personRepository.GetList(); |
||||
|
people.Any(p => !p.IsDeleted).ShouldBeTrue(); |
||||
|
people.Any(p => p.IsDeleted).ShouldBeFalse(); |
||||
|
} |
||||
|
|
||||
|
//Soft delete is disabled (restored previous state)
|
||||
|
people = _personRepository.GetList(); |
||||
|
people.Any(p => !p.IsDeleted).ShouldBeTrue(); |
||||
|
people.Any(p => p.IsDeleted).ShouldBeTrue(); |
||||
|
} |
||||
|
|
||||
|
//Soft delete is enabled (restored previous state)
|
||||
|
people = _personRepository.GetList(); |
||||
|
people.Any(p => !p.IsDeleted).ShouldBeTrue(); |
||||
|
people.Any(p => p.IsDeleted).ShouldBeFalse(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,26 +0,0 @@ |
|||||
using System.Linq; |
|
||||
using Shouldly; |
|
||||
using Volo.Abp.Domain.Repositories; |
|
||||
using Volo.Abp.TestApp.Domain; |
|
||||
using Xunit; |
|
||||
|
|
||||
namespace Volo.Abp.EntityFrameworkCore.Repositories |
|
||||
{ |
|
||||
public class SoftDelete_Filter_Tests : EntityFrameworkCoreTestBase |
|
||||
{ |
|
||||
private readonly IRepository<Person> _personRepository; |
|
||||
|
|
||||
public SoftDelete_Filter_Tests() |
|
||||
{ |
|
||||
_personRepository = GetRequiredService<IRepository<Person>>(); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void Should_Not_Get_Deleted_Entities_By_Default() |
|
||||
{ |
|
||||
var people = _personRepository.GetList(); |
|
||||
people.Count.ShouldBe(1); |
|
||||
people.Any(p => p.Name == "Douglas").ShouldBeTrue(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue