组合表达式树

Combining expression trees

我有以下表达式:

public Expression<Func<T, bool>> UserAccessCheckExpression<T>(int userId) where T : class
{
    return x => (IsAdmin || userId == CurrentUserId || userId == 0);
}

然后我想将此过滤器应用于多个集合 (IQueryable),例如:

return tasks
  .Where(t => t.TaskUsers
     .Any(x => UserAccessCheckExpression<TaskUser>(x.User) && x.SomeBool == true));

我在执行此操作时遇到以下错误:

Error 40 Cannot implicitly convert type System.Linq.Expressions.Expression<System.Func<TaskUser,bool>> to bool

我不能使用带有接口继承的解决方法(比如 TaskUser 继承带有 int UserId 属性 的接口(其中 T : IHasUserId)),因为我想组合逻辑。

问题是您的 UserAccessCheckExpression() 方法返回 ExpressionAny() 方法期望返回 boolean.

现在,您可以通过编译 Expression 并调用方法(使用 UserAccessCheckExpression<TaskUser>(x.User).Compile().Invoke(x.User)) 但这显然会在运行时失败,从而使您的代码 compile因为 Linq-to-Entities 无法将您的 Any() 转换为商店查询,因为它不再包含 Expression.

LinqKit 旨在使用它自己的 Invoke 扩展方法来解决这个问题,在让您的代码编译的同时,将确保您的 Expression 将被替换回其原始形式使用另一个名为 AsExpandable() 的扩展方法来扩展实体集。

试试这个:

using LinqKit.Extensions;

return tasks
      .AsExpandable()
      .Where(t => t.TaskUsers.Any(
                       x => UserAccessCheckExpression<TaskUser>(x.User).Invoke(x)
                            && x.SomeBool == true));

More on LinqKit

是的,所以,你不能那样做。 Expression<>Func<> 是有区别的。您正在尝试将 UserAccessCheckExpression 用作函数。我不确定你想做什么,但你可以将它编译成一个函数,然后像你这样使用它:

var expr = UserAccessCheckExpression<TaskUser>(x.User);
var func = expr.Compile();
// Later use it like ...
var result = func();

但我希望您将其与 EF 或 Linq2Sql 一起使用?在这种情况下,您需要重写表达式。它可以手动完成(不容易),或者更好的是,使用像 PredicateBuilder 这样的工具。