使用表达式树为LINQ查询构建IQueryable.Any

Ale*_*yte 9 c# expression-trees

我正在使用System.Linq.Expressions.Expression类动态构建SQL"WHERE"子句.它适用于简单的子句,例如添加"PhaseCode = X"子句,我执行以下操作:

var equalTarget = Expression.Constant(phaseCode, typeof(int?));
var phaseEquals = Expression.Equal(Expression.PropertyOrField(projParam, "PhaseCode"), equalTarget);
Run Code Online (Sandbox Code Playgroud)

但是,现在我正在尝试构建一个表达式,如果已将项目分配给特定组,则该表达式将返回记录.项目和集团有多对多的关系.如果没有表达式树,我会按如下方式执行:

db.Projects.Where(p => .... && p.GroupsAssigned.Any(g => g.ID == groupId))
Run Code Online (Sandbox Code Playgroud)

但是,我似乎找不到用Expression类表达的方法.实际上有两件事我想不通:

  • 如何遍历表之间的关系
  • 怎么办x.Any()

任何帮助是极大的赞赏.

use*_*116 14

调用扩展方法,如Enumerable.Any或Queryable.Any,只是对序列的静态方法调用以及为WHERE子句创建的lambda表达式.你可以Expression.Call这样做:

// for Enumerable.Any<T>(IEnumerable<T>,Predicate<T>)
var overload = typeof(Enumerable).GetMethods("Any")
                                 .Single(mi => mi.GetParameters().Count() == 2);
var call = Expression.Call(
    overload,
    Expression.PropertyOrField(projParam, "GroupsAssigned"),
    anyLambda);      
Run Code Online (Sandbox Code Playgroud)

因为Queryable.Any<T>,您需要将其转换为方法:

static Expression BuildAny<TSource>(Expression<Func<TSource, bool>> predicate)
{
    var overload = typeof(Queryable).GetMethods("Any")
                              .Single(mi => mi.GetParameters().Count() == 2);
    var call = Expression.Call(
        overload,
        Expression.PropertyOrField(projParam, "GroupsAssigned"),
        predicate);   

    return call;
}
Run Code Online (Sandbox Code Playgroud)

虽然这似乎很奇怪,你无法通过普通查询来做到这一点.