Linq动态附加与OR的Where子句 [英] Linq Dynamically append Where clauses with OR

查看:102
本文介绍了Linq动态附加与OR的Where子句的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试使用动态添加的where子句来构建一个linq查询。我有一个网页,一些复选框被选中以对应于您要搜索的字段:

I've been trying to build a linq query with dynamically added where clauses. I have a web page with a bunch of checkboxes that are selected to correspond to which fields you want to search:

我到目前为止有以下几点:

What I have so far is the following:

//This calls a select from table to construct the query which the where clauses will be added to
IQueryable<AutoCompleteRestultDto> query = GetAutocompleteResults();

if (FirstName == true || AllFields == true)
{
    Expression<Func<AutoCompleteRestultDto, bool>> firstNameFilter = c => terms.Any(t => c.FirstName.ToLower().Contains(t.ToLower()));
    query = query.Where(firstNameFilter);
}
if (LastName == true || AllFields == true)
{
    Expression<Func<AutoCompleteRestultDto, bool>> lastNameFilter = c => terms.Any(t => c.LastName.ToLower().Contains(t.ToLower()));
    query = query.Where(lastNameFilter);
}
if (KnownAs == true || AllFields == true)
{
    Expression<Func<AutoCompleteRestultDto, bool>> knownAsFilter = c => terms.Any(t => c.KnownAs.ToLower().Contains(t.ToLower()));
    query = query.Where(knownAsFilter);
}
// etc.

return query
       .Select(c => new ContactAutoCompleteModel
                {
                    label = c.FirstName + " " + c.LastName
                })
                .Take(15)
                .OrderBy(d => d.label)
                .ToList();

问题是这个解决方案需要所有表达式同时成立,即:where(子句1 AND子句2 AND子句3)

The problem is this solution requires all the expressions that are tacked on to simultaneously be true ie: where(clause1 AND clause2 AND clause3)

无法弄清楚如何将其更改为OR子句,即:where(clause1 OR clause2 OR clause3)

Can't figure out how to change this to OR clauses ie: where(clause1 OR clause2 OR clause3)

推荐答案

您正在链接 Enumerable.Where 在您发布的代码中调用。这就是为什么你得到AND效果。以下是使用谓词而不是表达式的 PredicateBuilder 的流氓

You are chaining Enumerable.Where calls in the code you posted. That's why you get the AND effect. This below is a poach of PredicateBuilder using predicates instead of expressions.

  public static class PredicateExtensions
  {
    public static Predicate<T> Or<T> (this Predicate<T> p1, Predicate<T> p2)
    {
      return obj => p1(obj) || p2(obj);
    }

    public static Predicate<T> And<T> (this Predicate<T> p1, Predicate<T> p2)
    {
      return obj => p1(obj) && p2(obj);
    }
    public static Predicate<T> False<T> () { return obj => false; }
    public static Predicate<T> True<T>  () { return obj => true; }

    public static Predicate<T> OrAll<T> (IEnumerable<Predicate<T>> conditions)
    {
      Predicate<T> result = PredicateExtensions.False<T>();
      foreach (Predicate<T> cond in conditions)
        result = result.Or<T>(cond);
      return result;
    }

    public static Predicate<T> AndAll<T> (IEnumerable<Predicate<T>> conditions)
    {
      Predicate<T> result = PredicateExtensions.True<T>();
      foreach (Predicate<T> cond in conditions)
        result = result.And<T>(cond);
      return result;
    }
  }

你可以使用上面这样一个枚举,在某些条件下自定义(apriori)谓词枚举:

You can use the above like so with an enumerable , customizing (apriori) the predicate enumerable on some condition:

Predicate<AutoCompleteRestultDto> firstNamePredicate = 
    c => terms.Any(t => c.FirstName.ToLower().Contains(t.ToLower()));
Predicate<AutoCompleteRestultDto> lastNamePredicate = 
    c => terms.Any(t => c.LastName.ToLower().Contains(t.ToLower()));
Predicate<AutoCompleteRestultDto> knownAsPredicate = 
    c => terms.Any(t => c.KnownAs.ToLower().Contains(t.ToLower()));
var all = new Predicate<AutoCompleteRestultDto>[] { 
    firstNamePredicate, 
    knownAsPredicate, 
    lastNamePredicate };
//
var items = query.Where(a => PredicateExtensions.OrAll(all)(a)).ToList();
items = query.Where(a => PredicateExtensions.AndAll(all)(a)).ToList();

或像您一样重复添加它们,一步一步:

or adding them iteratively like you do, step by step:

Predicate<AutoCompleteRestultDto> orResultPredicate = 
    PredicateExtensions.False<AutoCompleteRestultDto>();
if (FirstName == true || AllFields == true) {
    orResultPredicate=orResultPredicate.Or(firstNamePredicate); } 
if (LastName == true || AllFields == true) { 
    orResultPredicate = orResultPredicate.Or(lastNamePredicate); }
if (KnownAs == true || AllFields == true) { 
    orResultPredicate = orResultPredicate.Or(knownAsPredicate); }
Func<AutoCompleteRestultDto, bool> funcOr = c => orResultPredicate(c);
//
IQueryable<AutoCompleteRestultDto> query; // initialized already
var items = query.Where(funcOr).ToList(); 

这篇关于Linq动态附加与OR的Where子句的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆