【发布时间】:2021-09-02 04:21:39
【问题描述】:
我有一个基本过滤器类,它负责检查实体集合是否与其子类中定义的过滤器条件匹配:
public abstract class FilterInputBase<TEntity> : IFilterInput<TEntity>
{
public Expression<Func<TEntity, bool>> MatchesFilter()
{
var input = Expression.Variable(typeof(TEntity), "entity");
var expressions = GetFilterExpressions().ToList();
if(expressions.Count == 0)
expressions.Add(e => true);
// checks if the input satisfies all the filter conditions
var resultExpression = expressions.Aggregate(
(l, r) => Expression.Lambda<Func<TEntity, bool>>(
Expression.AndAlso(Expression.Invoke(l, input), Expression.Invoke(r, input)), input));
return resultExpression;
}
/// <summary>
/// Returns a list of filter conditions converted into Expressions
/// </summary>
/// <returns></returns>
protected abstract IEnumerable<Expression<Func<TEntity, bool>>> GetFilterExpressions();
}
这个类被用作:
public static IQueryable<TEntity> Filter<TEntity>(this IQueryable<TEntity> query, IFilterInput<TEntity> filterInput) =>
query.Where(filterInput?.MatchesFilter() ?? (x => true));
顾名思义,GetFilterExpressions 方法根据过滤器参数返回过滤器表达式的集合。这些过滤条件在MatchesFilter 方法中聚合形成一个过滤表达式:resultExpression。
此解决方案最多可使用两个过滤器表达式。现在我需要有两个以上的表达式。但是如果有更多的表达式,查询会在第二次尝试时失败。它适用于第一次运行。添加了更多表达式后,我收到以下错误:
"message": "An item with the same key has already been added. Key: entity",
"stackTrace": " at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)\n at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)\n at Microsoft.EntityFrameworkCore.Query.ExpressionEqualityComparer.ExpressionComparer.CompareLambda(LambdaExpression a, LambdaExpression b)\n at Microsoft.EntityFrameworkCore.Query.ExpressionEqualityComparer.ExpressionComparer.Compare(Expression left, Expression right)\n at Microsoft.EntityFrameworkCore.Query.ExpressionEqualityComparer.ExpressionComparer.CompareInvocation(InvocationExpression a, InvocationExpression b)\n at Microsoft.EntityFrameworkCore.Query.ExpressionEqualityComparer.ExpressionComparer.Compare(Expression left, Expression right)\n at Microsoft.EntityFrameworkCore.Query.ExpressionEqualityComparer.ExpressionComparer.CompareBinary(BinaryExpression a, BinaryExpression b)\n at Microsoft.EntityFrameworkCore.Query.ExpressionEqualityComparer.ExpressionComparer.Compare(Expression left, Expression right)\n at Microsoft.EntityFrameworkCore.Query.ExpressionEqualityComparer.ExpressionComparer.CompareLambda(LambdaExpression a, LambdaExpression b)\n at Microsoft.EntityFrameworkCore.Query.ExpressionEqualityComparer.ExpressionComparer.Compare(Expression left, Expression right)\n at Microsoft.EntityFrameworkCore.Query.ExpressionEqualityComparer.ExpressionComparer.CompareUnary(UnaryExpression a, UnaryExpression b)\n at Microsoft.EntityFrameworkCore.Query.ExpressionEqualityComparer.ExpressionComparer.Compare(Expression left, Expression right)\n at Microsoft.EntityFrameworkCore.Query.ExpressionEqualityComparer.ExpressionComparer.CompareExpressionList(IReadOnlyList`1 a, IReadOnlyList`1 b)\n at Microsoft.EntityFrameworkCore.Query.ExpressionEqualityComparer.ExpressionComparer.CompareMethodCall(MethodCallExpression a, MethodCallExpression b)\n at Microsoft.EntityFrameworkCore.Query.ExpressionEqualityComparer.ExpressionComparer.Compare(Expression left, Expression right)\n at Microsoft.EntityFrameworkCore.Query.ExpressionEqualityComparer.ExpressionComparer.CompareExpressionList(IReadOnlyList`1 a, IReadOnlyList`1 b)\n at Microsoft.EntityFrameworkCore.Query.ExpressionEqualityComparer.ExpressionComparer.CompareMethodCall(MethodCallExpression a, MethodCallExpression b)\n at Microsoft.EntityFrameworkCore.Query.ExpressionEqualityComparer.ExpressionComparer.Compare(Expression left, Expression right)\n at Microsoft.EntityFrameworkCore.Query.ExpressionEqualityComparer.Equals(Expression x, Expression y)\n at Microsoft.EntityFrameworkCore.Query.CompiledQueryCacheKeyGenerator.CompiledQueryCacheKey.Equals(CompiledQueryCacheKey other)\n at Microsoft.EntityFrameworkCore.Query.RelationalCompiledQueryCacheKeyGenerator.RelationalCompiledQueryCacheKey.Equals(RelationalCompiledQueryCacheKey other)\n at Microsoft.EntityFrameworkCore.SqlServer.Query.Internal.SqlServerCompiledQueryCacheKeyGenerator.SqlServerCompiledQueryCacheKey.Equals(SqlServerCompiledQueryCacheKey other)\n at Microsoft.EntityFrameworkCore.SqlServer.Query.Internal.SqlServerCompiledQueryCacheKeyGenerator.SqlServerCompiledQueryCacheKey.Equals(Object obj)\n at System.Collections.Concurrent.ConcurrentDictionary`2.TryGetValueInternal(TKey key, Int32 hashcode, TValue& value)\n at System.Collections.Concurrent.ConcurrentDictionary`2.TryGetValue(TKey key, TValue& value)\n at Microsoft.Extensions.Caching.Memory.MemoryCache.TryGetValue(Object key, Object& result)\n at Microsoft.Extensions.Caching.Memory.CacheExtensions.TryGetValue[TItem](IMemoryCache cache, Object key, TItem& value)\n at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)\n at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)\n at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)\n at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetAsyncEnumerator(CancellationToken cancellationToken)\n at System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable`1.GetAsyncEnumerator()\n at HotChocolate.Types.Pagination.QueryableOffsetPagingHandler`1.ExecuteQueryableAsync(IQueryable`1 queryable, CancellationToken cancellationToken)\n at HotChocolate.Types.Pagination.QueryableOffsetPagingHandler`1.ResolveAsync(IResolverContext context, IQueryable`1 queryable, OffsetPagingArguments arguments)\n at HotChocolate.Types.Pagination.OffsetPagingHandler.HotChocolate.Types.Pagination.IPagingHandler.SliceAsync(IResolverContext context, Object source)\n at HotChocolate.Types.Pagination.PagingMiddleware.InvokeAsync(IMiddlewareContext context)\n at HotChocolate.Utilities.MiddlewareCompiler`1.ExpressionHelper.AwaitTaskHelper(Task task)\n at HotChocolate.Data.ToListMiddleware`1.InvokeAsync(IMiddlewareContext context)\n at HotChocolate.Types.EntityFrameworkObjectFieldDescriptorExtensions.<>c__DisplayClass2_1`1.<<UseDbContext>b__4>d.MoveNext()\n--- End of stack trace from previous location where exception was thrown ---\n at HotChocolate.Types.EntityFrameworkObjectFieldDescriptorExtensions.<>c__DisplayClass2_1`1.<<UseDbContext>b__4>d.MoveNext()\n--- End of stack trace from previous location where exception was thrown ---\n at HotChocolate.AspNetCore.Authorization.AuthorizeMiddleware.InvokeAsync(IDirectiveContext context)\n at HotChocolate.Utilities.MiddlewareCompiler`1.ExpressionHelper.AwaitTaskHelper(Task task)\n at HotChocolate.Execution.Processing.ResolverTask.ExecuteResolverPipelineAsync(CancellationToken cancellationToken)\n at HotChocolate.Execution.Processing.ResolverTask.TryExecuteAsync(CancellationToken cancellationToken)"
我相信expressions.Aggregate() 可能不是正确的做法。有没有更好的方法来解决这个问题?另外,我需要清除任何缓存的字典吗?
【问题讨论】:
标签: c# .net-core entity-framework-core expression