Linq用OR动态附加Where子句

时间:2014-10-24 06:25:37

标签: c# linq entity-framework entity-framework-5

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

enter image description here

到目前为止我的内容如下:

//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(clause1 AND clause2 AND clause3)

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

1 个答案:

答案 0 :(得分:6)

您在所发布的代码中链接Enumerable.Where次来电。这就是你获得AND效果的原因。以下是使用谓词而不是表达式的PredicateBuilder的挖掘。

  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)谓词在某些条件下可枚举:

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();

或者像你一样迭代地添加它们,一步一步:

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();