具有嵌套属性的动态linq表达式树 [英] Dynamic linq expression tree with nested properties

查看:119
本文介绍了具有嵌套属性的动态linq表达式树的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个列表,必须对子属性进行过滤.过滤器运算符是动态的,我使用谓词生成器来组合多个过滤器/lambda.

I have a list which I must filter on child properties. The filter operator is dynamic and I'm using a predicate builder in order to combine several filters/lambdas.

为简单起见,假设我有两个这样的类:

For simplicity, let's say that I have two classes like this:

public class FirstClass
{
    public int Id { get; set; }
    public ICollection<SecondClass> MyList { get; set; }
}

public class SecondClass
{
    public int ReferenceId { get; set; }
    public int Value { get; set; }
}

我的过滤器使用参考ID,运算符类型和值,以便伪代码如下:

My filter use a reference id, an operator type and a value, such that a pseudo code would be like this:

"list of FirstClass".Where(param1 => 
    param1.MyList.Single(param2 => 
        param2.ReferenceId == "reference id").Value "operatorType" "value")

实际的过滤器将类似于123 eq 456,其中引用ID为123,operatorType为"eq",值为456.

The actual filter will be something like 123 eq 456, where the reference id is 123, operatorType is "eq" and value is 456.

如果运算符只是相等的,那么下面的方法就可以了:

If the operator just was equality, then the following works just fine:

Expression<Func<FirstClass, bool>> lambda = 
    param1 => param1.MyList.Single(param2 => param2.ReferenceId == id).Value == value;

此外,仅对具有动态表达式的FirstClass进行过滤,就像一个超级按钮一样工作,例如对ID进行过滤(我的ExpressionTypeDictionary是用于根据提供的operatorType选择ExpressionType的字典):

Also, filtering only on FirstClass with dynamic expressions, works like a charm, e.g. filtering on Id (my ExpressionTypeDictionary is a dictionary for selecting an ExpressionType based on the provided operatorType):

var parameter = Expression.Parameter(typeof(FirstClass), "param1");
Expression body = parameter;
body = Expression.Property(body, "Id");
body = Expression.MakeBinary(ExpressionTypeDictionary[operatorType], body, value);
var lambda = Expression.Lambda<Func<FirstClass, bool>>(body, new[] { parameter });

我可以编译以下内容,但是使用EF Core对实际数据执行过滤器将为querySource返回一个异常:

I'm able to get the following to compile, but executing the filter on real data using EF Core returns an exception for querySource:

var parameter = Expression.Parameter(typeof(FirstClass), "param1");
Expression<Func<FirstClass, int>> left = param1 => 
    param1.MyClass.Single(param2 => param2.ReferenceId == id).Value;
var body = Expression.MakeBinary(
    ExpressionTypeDictionary[operatorType], 
    left.Body, 
    Expression.Constant(value));
var lambda = Expression.Lambda<Func<FirstClass, bool>>(body, new[] { parameter });
...
theList.Where(lambda);

任何建议,我们都很感激:)

Any suggestions are appreciated :)

推荐答案

我认为不是这样的表达方式

I think rather than expression like this

Expression<Func<FirstClass, bool>> predicate = 
    x => x.MyList.Single(y => y.ReferenceId == id).Value [operator] value;

您最好构建这样的表达式:

you'd better build an expression like this:

Expression<Func<FirstClass, bool>> predicate = 
    x => x.MyList.Any(y => y.ReferenceId == id && y.Value == value);

这是您可以执行的操作:

Here is how you can do that:

var innerParameter = Expression.Parameter(typeof(SecondClass), "y");
var innerPredicate = Expression.Lambda<Func<SecondClass, bool>>(
    Expression.AndAlso(
        Expression.Equal(Expression.Property(innerParameter, "ReferenceId"), Expression.Constant(id)),
        Expression.MakeBinary(ExpressionTypeDictionary[operatorType], Expression.Property(innerParameter, "Value"), Expression.Constant(value))),
    innerParameter);
var parameter = Expression.Parameter(typeof(FirstClass), "x");
var predicate = Expression.Lambda<Func<FirstClass, bool>>(
    Expression.Call(
        typeof(Enumerable), "Any", new Type[] { typeof(SecondClass) },
        Expression.Property(parameter, "MyList"), innerPredicate),
    parameter);

这篇关于具有嵌套属性的动态linq表达式树的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆