C# 构建动态表达式树以筛选集合属性

C# 构建动态表达式树以筛选集合属性,c#,wcf,entity-framework,lambda,filtering,C#,Wcf,Entity Framework,Lambda,Filtering,我正在尝试构建一个lambda表达式,它将与其他表达式组合到一个相当大的表达式树中进行过滤。在我需要按子集合属性进行筛选之前,这一切都很正常 如何构建一个Lambda表达式,该表达式将对作为根对象属性的集合的属性使用Any()进行过滤 例如: CurrentDataSource.Offices.Where(o => o.base_Trades.Any(t => t.Name == "test")) 这就是我静态构建表达式的方式,但我需要动态构建它。很抱歉给你带来了困惑 编辑:以下是

我正在尝试构建一个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);
IQueryable officeQuery=CurrentDataSource.Offices.AsQueryable();
ParameterExpression pe=Expression.Parameter(办公室的类型),“办公室”);
ParameterExpression tpe=Expression.Parameter(交易类型),“交易”);
表达式SimpleWhere=null;
表达式ComplexWhere=null;
foreach(ssfo中的ServerSideFilterObject fo)
{
SimpleWhere=null;
foreach(fo.FilterValues中的字符串值)
{
如果(!CollectionProperties.Contains(fo.PropertyName))
{
//在这里处理单例lambda逻辑。
Expression left=Expression.Property(pe,typeof(Office).GetProperty(fo.PropertyName));
表达式右=表达式常数(值);
if(SimpleWhere==null)
{
SimpleWhere=表达式.Equal(左、右);
}
其他的
{
表达式e1=表达式.Equal(左、右);
SimpleWhere=Expression.Or(SimpleWhere,e1);
}
}
其他的
{
//在这里处理内部集合lambda逻辑。
Expression left=Expression.Property(tpe,typeof(Trades).GetProperty(“Name”);
表达式右=表达式常数(值);
表达式InnerLambda=表达式.Equal(左、右);
//问题领域。
Expression OfficeAndProperty=Expression.Property(pe,typeof(Office).GetProperty(fo.PropertyName));
Expression OuterLambda=Expression.Call(OfficeAndProperty,typeof(Trades).GetMethod(“Any”,新类型[]{typeof(Expression)}),InnerLambda);
if(SimpleWhere==null)
SimpleWhere=外部lambda;
其他的
SimpleWhere=Expression.Or(SimpleWhere,OuterLambda);
}
}
if(ComplexWhere==null)
ComplexWhere=SimpleWhere;
其他的
ComplexWhere=Expression.And(ComplexWhere,SimpleWhere);
}
MethodCallExpression whereCallExpression=Expression.Call(typeof(Queryable),“Where”,新类型[]{officeQuery.ElementType},officeQuery.Expression,Expression.Lambda(ComplexWhere,新参数Expression[]{pe});
结果=officeQuery.Provider.CreateQuery(whereCallExpression);

您列出的示例将根据您的评论起作用。以下是我的工作示例:

Templates.Where(t => t.TemplateFields.Any(f => f.Required == 'Y'))
我们有具有特定字段集合的模板,这些字段可能是必需的。因此,我可以在上面的语句需要任何字段的地方获得模板

希望这能有所帮助…或者至少能证实你正在努力做什么。如果你对此有更多问题,请告诉我,我会详细说明

祝你好运

提供的代码

CurrentDataSource.Offices.Where(o => o.base_Trades.Any(t => t.Name == "test"))
只要
o.base\u交易
实现
IEnumerable
,就应该有效。如果
o.base\u Trades
仅实现
IEnumerable
,如果可以确保
o.base\u Trades
中的所有元素都属于您的
Trade
类型,或者如果可能存在其他(不兼容)类型的元素,则需要使用
Cast()

然后看起来是这样的:

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

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

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);
Expression left=Expression.Property(tpe,typeof(Trades).GetProperty(“Name”);
表达式右=表达式常数(值);
表达式InnerLambda=表达式.Equal(左、右);
表达式innerFunction=Expression.Lambda(InnerLambda,tpe);
method=typeof(可枚举).GetMethods()。其中(m=>m.Name==“Any”和&m.GetParameters()。Length==2)。Single().MakeGenericMethod(typeof(Trades));
OuterLambda=Expression.Call(方法,Expression.Property(pe,typeof(Office).GetProperty(fo.PropertyName)),innerFunction);

请不要这样做,您真正希望它使用的是一个名为dynamic linq的库


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

您是在问如何构建表达式树吗?我不确定您的示例中的层次结构是如何工作的。你能再详细说明一下吗?办公室是根,然后每个办公室都有一个交易集合吗?你想过滤交易的名称吗??过滤器是我有点迷路的地方。抱歉,不是,我只是不确定用于构建带有内部方法调用的表达式和参数表达式的语法。在本例中,我得到一个错误,指出由于我的参数与定义不匹配,无法找到Any()。在这种情况下,我不确定这是否是因为我不懂语法,或者我使用它的方式是否不支持Any()。我正在尝试根据集合中每个交易对象的Name属性筛选集合。这与我正在使用的类似,但我必须使用反射动态构建lamda表达式,以便确保筛选器包含集合中的其他筛选器。这是一个优秀的库,我也使用它,但它不支持例如对集合属性的属性进行排序,如
myIQueryable.OrderBy(x=>x.MyCollection.Select(y=>y.Myproperty))
,至少我无法将其发送到w