c# - Linq 用 OR 动态追加 Where 子句

标签 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)

最佳答案

您正在将 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;
    }
  }

您可以像这样使用 enumerable ,在某些条件下自定义(先验)可枚举的谓词:

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

关于c# - Linq 用 OR 动态追加 Where 子句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26542555/

相关文章:

c# - 等效于 DbContext 上的 ObjectContext.AddObject(entityName, entity)

c# - AsNoTracking() 的全局设置?

c# - 如何使 Windows 窗体上的 dataGridView 中的最后一行始终显示,同时仍允许剩余行滚动

c# - c#.net 数组中的平滑曲线

c# - "Turning"一个 IEnumerable<IEnumerable<T>> 90 度

c# - where if 语句在 linq 查询 c#

c# - POST 调用时不保存工作单元

c# - 客户端 Blazor 表单提交两次

c# - 将单元测试写入程序集或单独的程序集中?

c# - 在通用列表中搜索项目时,我应该使用 LINQ 还是 Contains?