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

14

我正在使用System.Linq.Expressions.Expression类动态构建SQL的“WHERE”子句。对于简单的子句,它可以正常工作,例如要添加“PhaseCode = X”子句,我需要执行以下操作:

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

然而,现在我正在尝试构建一个表达式,如果项目已经分配给特定组,则返回该记录。 项目和组之间有多对多关系。 没有表达式树,我将按以下方式完成:

db.Projects.Where(p => .... && p.GroupsAssigned.Any(g => g.ID == groupId))

然而,我似乎找不到一种使用Expression类表达的方法。

  • 如何遍历表格之间的关系
  • 如何使用x.Any()

非常感谢您的任何帮助。

1个回答

18

调用扩展方法,例如Enumerable.AnyQueryable.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);      

对于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;
}

虽然这似乎很奇怪,你无法通过普通查询来完成这个任务。


感谢您的解决方案,sixlettervariables。Expression.Call()正是我所需要的。回答您的问题,我在这种情况下无法进行普通查询,因为我不知道编译时WHERE语句中会有多少个AND部分。这完全取决于用户在搜索表单中所做的选择。构建表达式树似乎是唯一有效的解决方案。 - Alec Bryte
感谢上帝,我看到了这个错误。我的错误在于我调用了typeof(Queryable).GetMethods("Any").Single(mi => mi.GetParameters().Count() == 2);而不是:typeof(Enumerable).GetMethods("Any").Single(mi => mi.GetParameters().Count() == 2); - David Diez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接