正在构建动态表达式树以对集合属性进行筛选
本文关键字:属性 集合 筛选 构建 动态 表达式 | 更新日期: 2023-09-27 18:21:06
我正在尝试构建一个lambda表达式,该表达式将与其他表达式组合到一个相当大的表达式树中进行筛选。在我需要通过子集合属性进行筛选之前,此操作一直很好。
如何构建一个Lambda表达式,该表达式将使用Any()对作为根对象属性的集合的属性进行筛选?
示例:
CurrentDataSource.Offices.Where(o => o.base_Trades.Any(t => t.Name == "test"))
这就是我静态构建表达式的方式,但我需要动态构建它。很抱歉造成混乱。
编辑:以下是我如何处理不那么复杂的表达式的片段:
IQueryable<Office> officeQuery = CurrentDataSource.Offices.AsQueryable<Office>();
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<Office, bool>>(ComplexWhere, new ParameterExpression[] { pe }));
results = officeQuery.Provider.CreateQuery<Office>(whereCallExpression);
找到了解决方案。我以前并没有在合适的地方寻找任何方法。
Expression left = Expression.Property(tpe, typeof(Trades).GetProperty("Name"));
Expression right = Expression.Constant(value);
Expression InnerLambda = Expression.Equal(left, right);
Expression<Func<Trades, bool>> innerFunction = Expression.Lambda<Func<Trades, bool>>(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<Trade>
,就应该工作。如果o.base_Trades
只实现了IEnumerable
,那么如果可以确保o.base_Trades
中的所有元素都是您的Trade
类型,则需要使用Cast<Trade>()
;如果可能存在其他(不兼容)类型的元素,则使用OfType<Trade>()
。
然后看起来是这样的:
CurrentDataSource.Offices
.Where(o => o.base_Trades.Cast<Trade>.Any(t => t.Name == "test"))