mirror of https://github.com/abpframework/abp.git
Browse Source
Add `HasAbpQueryFilter` method to combine the custom filter with global filters.pull/17156/head
committed by
GitHub
9 changed files with 160 additions and 38 deletions
@ -0,0 +1,27 @@ |
|||||
|
using System; |
||||
|
using System.Linq.Expressions; |
||||
|
using Microsoft.EntityFrameworkCore.Metadata.Builders; |
||||
|
using Microsoft.EntityFrameworkCore.Metadata.Internal; |
||||
|
|
||||
|
namespace Volo.Abp.EntityFrameworkCore; |
||||
|
|
||||
|
public static class EntityTypeBuilderExtensions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// This method is used to add a query filter to this entity which combine with ABP EF Core builtin query filters.
|
||||
|
/// </summary>
|
||||
|
/// <returns></returns>
|
||||
|
public static EntityTypeBuilder<TEntity> HasAbpQueryFilter<TEntity>(this EntityTypeBuilder<TEntity> builder, Expression<Func<TEntity, bool>> filter) |
||||
|
where TEntity : class |
||||
|
{ |
||||
|
#pragma warning disable EF1001
|
||||
|
var queryFilterAnnotation = builder.Metadata.FindAnnotation(CoreAnnotationNames.QueryFilter); |
||||
|
#pragma warning restore EF1001
|
||||
|
if (queryFilterAnnotation != null && queryFilterAnnotation.Value != null && queryFilterAnnotation.Value is Expression<Func<TEntity, bool>> existingFilter) |
||||
|
{ |
||||
|
filter = QueryFilterExpressionHelper.CombineExpressions(filter, existingFilter); |
||||
|
} |
||||
|
|
||||
|
return builder.HasQueryFilter(filter); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
using System; |
||||
|
using System.Linq.Expressions; |
||||
|
|
||||
|
namespace Volo.Abp.EntityFrameworkCore; |
||||
|
|
||||
|
public static class QueryFilterExpressionHelper |
||||
|
{ |
||||
|
public static Expression<Func<T, bool>> CombineExpressions<T>(Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2) |
||||
|
{ |
||||
|
var parameter = Expression.Parameter(typeof(T)); |
||||
|
|
||||
|
var leftVisitor = new ReplaceExpressionVisitor(expression1.Parameters[0], parameter); |
||||
|
var left = leftVisitor.Visit(expression1.Body); |
||||
|
|
||||
|
var rightVisitor = new ReplaceExpressionVisitor(expression2.Parameters[0], parameter); |
||||
|
var right = rightVisitor.Visit(expression2.Body); |
||||
|
|
||||
|
return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(left!, right!), parameter); |
||||
|
} |
||||
|
|
||||
|
private class ReplaceExpressionVisitor : ExpressionVisitor |
||||
|
{ |
||||
|
private readonly Expression _oldValue; |
||||
|
private readonly Expression _newValue; |
||||
|
|
||||
|
public ReplaceExpressionVisitor(Expression oldValue, Expression newValue) |
||||
|
{ |
||||
|
_oldValue = oldValue; |
||||
|
_newValue = newValue; |
||||
|
} |
||||
|
|
||||
|
public override Expression Visit(Expression node) |
||||
|
{ |
||||
|
return node == _oldValue ? _newValue : base.Visit(node); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,36 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.Data; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
using Volo.Abp.TestApp.Domain; |
||||
|
using Volo.Abp.TestApp.Testing; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.EntityFrameworkCore.DataFiltering; |
||||
|
|
||||
|
public class EfCore_Custom_Filter_Tests : TestAppTestBase<AbpEntityFrameworkCoreTestModule> |
||||
|
{ |
||||
|
private readonly IBasicRepository<Category, Guid> _categoryRepository; |
||||
|
|
||||
|
public EfCore_Custom_Filter_Tests() |
||||
|
{ |
||||
|
_categoryRepository = GetRequiredService<IBasicRepository<Category, Guid>>(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_Combine_Abp_And_Custom_QueryFilter_Test() |
||||
|
{ |
||||
|
var categories = await _categoryRepository.GetListAsync(); |
||||
|
categories.Count.ShouldBe(1); |
||||
|
categories[0].Name.ShouldBe("abp.cli"); |
||||
|
|
||||
|
using (GetRequiredService<IDataFilter<ISoftDelete>>().Disable()) |
||||
|
{ |
||||
|
categories = await _categoryRepository.GetListAsync(); |
||||
|
categories.Count.ShouldBe(2); |
||||
|
categories.ShouldContain(x => x.Name == "abp.cli" && x.IsDeleted == false); |
||||
|
categories.ShouldContain(x => x.Name == "abp.core" && x.IsDeleted == true); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Domain.Entities; |
||||
|
|
||||
|
namespace Volo.Abp.TestApp.Domain; |
||||
|
|
||||
|
public class Category : AggregateRoot<Guid>, ISoftDelete |
||||
|
{ |
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
public bool IsDeleted { get; set; } |
||||
|
} |
||||
Loading…
Reference in new issue