如果这是一个简单的问题,我深表歉意;假设我有一个带有 2 个方法的 EF 查询对象:
public static IQueryable<Animal> FourLegged(this IQueryable<Animal> query)
{
return query.Where(r => r.NumberOfLegs == 4);
}
public static IQueryable<Animal> WithoutTail(this IQueryable<Animal> query)
{
return query.Where(r => !r.HasTail);
}
现在,在我的服务层中,要获得四足且没有尾部的动物,我可以这样做:
_animalService.Query()
.FourLegged()
.WithoutTail();
这将产生如下所示的 sql 查询:
select * from Animal where NumberOfLegs = 4 AND HasTail = 0
如何使用带有 OR 的 2 种查询方法?我想要四足动物或没有尾部的动物
select * from Animal where NumberOfLegs = 4 OR HasTail = 0
在 Nhibernate 中,我会使用简单的析取,但在 EF 中找不到。
谢谢
解决方案:我最终使用了 LinqKit predicates mentioned on this answer 。它工作得很好,我也可以重用谓词。
最佳答案
当您已经调用 query.Where()
时,您实际上无法执行此操作。那里的谓词已经收集在 IQueryable
中。它们都由 AND
组合而成.
为了获得OR
你必须制作一个query.Where()
调用并传递涵盖各种析取谓词的单个表达式。
在您的情况下,组合谓词将如下所示:
query.Where(r => (r.NumberOfLegs == 4) || (!r.HasTail))
为了使其更加动态,您本质上需要构建一个自定义表达式组合函数,其工作方式如下:
Expression<Func<Animal, bool>> fourLegged = r => r.NumberOfLegs == 4;
Expression<Func<Animal, bool>> withoutTail = r => !r.HasTail;
query = query.Where(CombineDisjunctivePredicates(fourLegged, withoutTail));
所以我们写 CombineDisjunctivePredicates
功能:
public Expression<Func<T, bool>> CombineDisjunctivePredicates<T>(params Expression<Func<T, bool>>[] predicates)
{
Expression current = Expression.Constant(false);
ParameterExpression param = Expression.Parameter(typeof(T), "obj");
foreach (var predicate in predicates)
{
var visitor = new ReplaceExpressionVisitor(predicate.Parameters[0], param);
current = Expression.Or(current, visitor.Visit(predicate.Body));
}
return Expression.Lambda<Func<T, bool>>(current, param);
}
这基本上采用多个谓词,并通过使用 bool OR 组合表达式体来组合它们。由于我们要组合可能具有不同表达式参数的不同表达式,因此我们还需要确保使用公共(public)参数替换表达式主体中的所有表达式参数引用。我们使用简单的ReplaceExpressionVisitor
来做到这一点,很容易实现,如下所示:
public class ReplaceExpressionVisitor : ExpressionVisitor
{
private readonly Expression _original;
private readonly Expression _replacement;
public ReplaceExpressionVisitor(Expression original, Expression replacement)
{
_original = original;
_replacement = replacement;
}
public override Expression Visit(Expression node)
{
return node == _original ? _replacement : base.Visit(node);
}
}
这就是组合谓词所需的全部内容。您只需要确保现在更改您的方法,这样它们就不会调用 query.Where
但返回 Expression<Func<Animal, bool>>
相反。
关于c# - 如何获得 2 个 IQueryable<T> 方法来实现析取?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35648669/