繁体   English   中英

System.InvalidOperationException:从范围``引用的类型''的变量'',但未定义

[英]System.InvalidOperationException: Variable '' of type '' referenced from scope '', but it is not defined

我正在尝试使用在C#中使用表达式的实体框架全局过滤器。 我可以对期望的表达式进行单个或组合的表达而不会出现任何问题。

我使用以下模型构建器中的属性对所有实体应用查询过滤器

  1. 创建具有属性的虚拟类,将为其应用查询过滤器。 (即IsActive)
  2. 使用“ VisitMember()”覆盖具有该伪类的表达式,以创建新表达式,该表达式实际上将伪类的成员转换为实体类型。

注意:我尝试应用简单的查询拟合器,例如“ i => i.IsActive == true”。 使用“ AndAlso”的单个表达式和组合表达式都面临此错误。

选中后,预期查询过滤器已应用到各个表,没有任何错误。 我将从DbContext调用我的modelbuilder扩展方法,如下所示

DbContext中的代码:

modelBuilder.GlobalFilters<FilterColumns>(i => i.TenantId == 1, nameof(FilterColumns.TenantId));

我的自定义课程:

public class FilterColumns
{
   public int TenantId {get; set;}
}

我的ModelBuilder扩展方法:

    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)

提前致谢。

Lambda表达式参数是由实例绑定的,而不是根据代码所希望的名称。

您基本上需要首先创建一个参数表达式实例,将其传递给表达式访问者,并在内部使用它绑定映射的成员表达式,最后在创建新的lambda表达式时使用它。

因此,修改访问者类,如下所示:

public class CustomExpressionVisitor : ExpressionVisitor
{
    private readonly Type entityType;
    private readonly Type baseEntityType;
    private readonly ParameterExpression param;

    public CustomExpressionVisitor(Type entityType, Type baseEntityType, ParameterExpression param)
    {
        this.entityType = entityType;
        this.baseEntityType = baseEntityType;
        this.param = param;
    }
    protected override Expression VisitMember(MemberExpression expression)
    {
        if (expression.Member.DeclaringType == this.baseEntityType)
        {
            return Expression.PropertyOrField(this.param, expression.Member.Name);
        }

        return base.VisitMember(expression);
    }
}

调用代码为:

var param = Expression.Parameter(entity, "e");
var expressionVisitor = new CustomExpressionVisitor(entity, baseType, param);
var customExpression = expressionVisitor.Visit(expression?.Body);
var lambdaExpression = Expression.Lambda(customExpression, param);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM