我正在尝试使用 c# 中的表达式来使用实体框架全局过滤器。我可以毫无问题地构建单个或组合表达式的预期表达式。
我使用模型构建器中的属性为所有实体应用了查询过滤器,如下所示
- 创建了一个具有属性的虚拟类,将对其应用查询过滤器。(即IsActive)
- 使用“VisitMember()”覆盖该虚拟类的表达式以创建新表达式,该表达式实际上将虚拟类的成员转换为实体类型。
注意:我尝试应用简单的查询过滤器,例如“i => i.IsActive == true”。使用“AndAlso”的单个表达式和组合表达式都面临此错误。
经检查,预期的查询过滤器已应用于各个表,没有任何错误。我将从我的 DbContext 调用我的模型构建器扩展方法,如下所示
DbContext 中的代码:
modelBuilder.GlobalFilters<FilterColumns>(i => i.TenantId == 1, nameof(FilterColumns.TenantId));
我的自定义类:
public class FilterColumns
{
public int TenantId {get; set;}
}
我的模型构建器扩展方法:
public static void GlobalFilters<TClass>(this ModelBuilder modelBuilder, Expression<Func<TClass, bool>> expression, string property)
{
var body = expression?.Body;
var baseType = expression?.GetType().GetGenericArguments().FirstOrDefault()?.GetGenericArguments().FirstOrDefault();
var propertyType = baseType?.GetProperty(property)?.PropertyType;
if (body != null)
{
if (property != null)
{
var allEntities = modelBuilder?.Model.GetEntityTypes().Where(e => e.FindProperty(property) != null).Select(e => e.ClrType).ToList();
if (allEntities != null)
{
foreach (var entity in allEntities)
{
var entityPropertyType = entity?.GetProperty(property)?.PropertyType;
if (entityPropertyType == propertyType)
{
var param = expression?.Parameters.Single().ToString();
var expressionVisitor = new CustomExpressionVisitor(entity, baseType, param.ToString());
var customExpression = expressionVisitor.Visit(expression?.Body);
var lambdaExpression = Expression.Lambda(customExpression, param);
modelBuilder?.Entity(entity).HasQueryFilter(lambdaExpression);
}
}
}
}
}
}
CustomExpressionVisitor 类:
public class CustomExpressionVisitor : ExpressionVisitor
{
private readonly Type entityType;
private readonly Type baseEntityType;
private readonly string param;
public CustomExpressionVisitor(Type entityType, Type baseEntityType, string param)
{
this.entityType = entityType;
this.baseEntityType = baseEntityType;
this.param = param;
}
protected override Expression VisitMember(MemberExpression expression)
{
if (expression.Member.DeclaringType == this.baseEntityType)
{
var convertedParam = Expression.Parameter(entityType, this.param);
return Expression.PropertyOrField(convertedParam, expression.Member.Name);
}
return base.VisitMember(expression);
}
}
我已经通过应用查询过滤器期望从表中得到结果,但是当我尝试使用 linq 查询从表中访问数据时,我收到以下错误。您能提出解决此错误的解决方案吗?
at System.Linq.Expressions.Compiler.VariableBinder.Reference(ParameterExpression node, VariableStorageKind storage)
at System.Linq.Expressions.Compiler.VariableBinder.VisitParameter(ParameterExpression node)
at System.Linq.Expressions.ParameterExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
at System.Linq.Expressions.ExpressionVisitor.VisitMember(MemberExpression node)
at System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
at System.Linq.Expressions.ExpressionVisitor.VisitBinary(BinaryExpression node)
at System.Linq.Expressions.BinaryExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
at System.Linq.Expressions.ExpressionVisitor.Visit(ReadOnlyCollection`1 nodes)
at System.Linq.Expressions.Compiler.VariableBinder.VisitLambda[T](Expression`1 node)
at System.Linq.Expressions.Expression`1.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
at System.Linq.Expressions.ExpressionVisitor.Visit(ReadOnlyCollection`1 nodes)
at System.Linq.Expressions.Compiler.VariableBinder.VisitLambda[T](Expression`1 node)
at System.Linq.Expressions.Expression`1.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.Compiler.VariableBinder.Visit(Expression node)
at System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda)
at System.Linq.Expressions.Expression`1.Compile(Boolean preferInterpretation)
at System.Linq.Expressions.Expression`1.Compile()
at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.CreateExecutorLambda[TResults]()
at Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.CreateExecutorLambda[TResults]()
at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.CreateQueryExecutor[TResult](QueryModel queryModel)
at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](QueryModel queryModel)
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](Expression query, IQueryModelGenerator queryModelGenerator, IDatabase database, IDiagnosticsLogger`1 logger, Type contextType)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass13_0`1.<Execute>b__0()
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
at Remotion.Linq.QueryableBase`1.GetEnumerator()
at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.System.Collections.Generic.IEnumerable<TEntity>.GetEnumerator()
at System.Collections.Generic.List`1.AddEnumerable(IEnumerable`1 enumerable)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
提前致谢。