问题描述
我有一个列表,必须对子属性进行过滤.过滤器运算符是动态的,我使用谓词生成器来组合多个过滤器/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表达式树的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!