构建动态表达式树以过滤集合属性

我正在尝试构建一个lambda表达式,它将与其他表达式组合成一个相当大的表达式树进行过滤。 这工作正常,直到我需要通过子集合属性进行过滤。

如何构建一个Lambda表达式,它将在集合的属性上使用Any()进行过滤,该集合属性是根对象的属性?

例:

CurrentDataSource.Offices.Where(o => o.base_Trades.Any(t => t.Name == "test")) 

这是我如何静态构建表达式,但我需要动态构建它。 对困惑感到抱歉。

编辑:这是我如何处理不太复杂的表达式的片段:

 IQueryable officeQuery = CurrentDataSource.Offices.AsQueryable(); ParameterExpression pe = Expression.Parameter(typeof(Office), "Office"); ParameterExpression tpe = Expression.Parameter(typeof(Trades), "Trades"); Expression SimpleWhere = null; Expression ComplexWhere = null; foreach (ServerSideFilterObject fo in ssfo) { SimpleWhere = null; foreach (String value in fo.FilterValues) { if (!CollectionProperties.Contains(fo.PropertyName)) { //Handle singleton lambda logic here. Expression left = Expression.Property(pe, typeof(Office).GetProperty(fo.PropertyName)); Expression right = Expression.Constant(value); if (SimpleWhere == null) { SimpleWhere = Expression.Equal(left, right); } else { Expression e1 = Expression.Equal(left, right); SimpleWhere = Expression.Or(SimpleWhere, e1); } } else { //handle inner Collection lambda logic here. Expression left = Expression.Property(tpe, typeof(Trades).GetProperty("Name")); Expression right = Expression.Constant(value); Expression InnerLambda = Expression.Equal(left, right); //Problem area. Expression OfficeAndProperty = Expression.Property(pe, typeof(Office).GetProperty(fo.PropertyName)); Expression OuterLambda = Expression.Call(OfficeAndProperty, typeof(Trades).GetMethod("Any", new Type[] { typeof(Expression) } ),InnerLambda); if (SimpleWhere == null) SimpleWhere = OuterLambda; else SimpleWhere = Expression.Or(SimpleWhere, OuterLambda); } } if (ComplexWhere == null) ComplexWhere = SimpleWhere; else ComplexWhere = Expression.And(ComplexWhere, SimpleWhere); } MethodCallExpression whereCallExpression = Expression.Call(typeof(Queryable), "Where", new Type[] { officeQuery.ElementType }, officeQuery.Expression, Expression.Lambda<Func>(ComplexWhere, new ParameterExpression[] { pe })); results = officeQuery.Provider.CreateQuery(whereCallExpression); 

找到了解决方案。 我之前没有在正确的地方寻找任何方法。

 Expression left = Expression.Property(tpe, typeof(Trades).GetProperty("Name")); Expression right = Expression.Constant(value); Expression InnerLambda = Expression.Equal(left, right); Expression> innerFunction = Expression.Lambda>(InnerLambda, tpe); method = typeof(Enumerable).GetMethods().Where(m => m.Name == "Any" && m.GetParameters().Length == 2).Single().MakeGenericMethod(typeof(Trades)); OuterLambda = Expression.Call(method, Expression.Property(pe, typeof(Office).GetProperty(fo.PropertyName)),innerFunction); 

请不要这样做,你真正希望它使用一个名为dynamic linq的库。 http://nuget.org/packages/DynamicLINQ

您可以将查询存储为字符串,并且它支持非常复杂的查询。 表达树是一场噩梦。

您列出的示例将根据您的评论工作。 这是我合作的一个例子:

 Templates.Where(t => t.TemplateFields.Any(f => f.Required == 'Y')) 

我们有具有特定字段集合的模板,可能需​​要这些字段。 所以我可以获得上面那个语句需要任何字段的模板。

希望这有助于…或至少证实你正在尝试做什么。 如果您对此有更多疑问,请告诉我,我会详细说明。

祝好运!

提供的代码

 CurrentDataSource.Offices.Where(o => o.base_Trades.Any(t => t.Name == "test")) 

应该工作,只要o.base_Trades实现IEnumerable 。 如果o.base_Trades只实现IEnumerable ,你需要使用Cast()如果你可以确定o.base_Trades中的所有元素都是你的Trade类型或o.base_Trades OfType()如果可能有元素其他(不兼容)类型。

那将是这样的:

 CurrentDataSource.Offices .Where(o => o.base_Trades.Cast.Any(t => t.Name == "test"))