具有嵌套属性的动态linq表达式树

我有一个列表,我必须过滤子属性。 filter运算符是动态的,我正在使用谓词构建器来组合多个filter/ lambdas。

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

public class FirstClass { public int Id { get; set; } public ICollection MyList { get; set; } } public class SecondClass { public int ReferenceId { get; set; } public int Value { get; set; } } 

我的filter使用引用ID,运算符类型和值,这样伪代码就像这样:

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

实际的filter类似于123 eq 456 ,其中引用id为123,operatorType为“eq”,值为456。

如果运算符只是相等,那么以下工作正常:

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

此外,仅使用动态表达式对FirstClass进行过滤,就像魅力一样,例如过滤Id(我的ExpressionTypeDictionary是用于根据提供的operatorType选择ExpressionType的字典):

 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>(body, new[] { parameter }); 

我能够得到以下内容进行编译,但是使用EF Core对实际数据执行filter会返回querySource的exception:

 var parameter = Expression.Parameter(typeof(FirstClass), "param1"); Expression<Func> 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>(body, new[] { parameter }); ... theList.Where(lambda); 

任何建议值得赞赏:)

我想而不是像这样表达

 Expression> predicate = x => x.MyList.Single(y => y.ReferenceId == id).Value [operator] value; 

你最好建立一个这样的表达式:

 Expression> predicate = x => x.MyList.Any(y => y.ReferenceId == id && y.Value == value); 

以下是如何做到这一点:

 var innerParameter = Expression.Parameter(typeof(SecondClass), "y"); var innerPredicate = Expression.Lambda>( 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>( Expression.Call( typeof(Enumerable), "Any", new Type[] { typeof(SecondClass) }, Expression.Property(parameter, "MyList"), innerPredicate), parameter);