使用LINQ扩展方法的多个WHERE子句

use*_*886 71 c# linq

我有一个LINQ查询,如下所示:

DateTime today = DateTime.UtcNow;
var results = from order in context.Orders
              where ((order.OrderDate <= today) && (today <= order.OrderDate))
              select order;
Run Code Online (Sandbox Code Playgroud)

我正在努力学习/了解LINQ.在某些情况下,我需要添加两个额外的WHERE子句.为了做到这一点,我正在使用:

if (useAdditionalClauses)
{
  results = results.Where(o => o.OrderStatus == OrderStatus.Open)  // Now I'm stuck.
}
Run Code Online (Sandbox Code Playgroud)

如您所见,我知道如何添加额外的WHERE子句.但是我该如何添加多个?例如,我想补充一下

WHERE o.OrderStatus == OrderStatus.Open AND o.CustomerID == customerID

到我以前的查询.如何使用扩展方法执行此操作?

谢谢!

Dav*_*vid 135

两种方式:

results = results.Where(o => (o.OrderStatus == OrderStatus.Open) &&
                             (o.CustomerID == customerID));
Run Code Online (Sandbox Code Playgroud)

要么:

results = results.Where(o => (o.OrderStatus == OrderStatus.Open))
                 .Where(o => (o.CustomerID == customerID));
Run Code Online (Sandbox Code Playgroud)

我通常更喜欢后者.但是值得分析SQL服务器来检查查询执行情况,看看哪一个对您的数据表现更好(如果有任何差异).

关于链接.Where()方法的注释:您可以将所需的所有LINQ方法链接在一起.类似的方法.Where()实际上并没有针对数据库执行(尚未).它们推迟执行直到计算实际结果(例如使用a .Count()或a .ToList()).因此,当您将多个方法(更多调用.Where(),可能是某个.OrderBy()或某些内容等)链接在一起时,它们会构建所谓的表达式树.整个树是在评估它时对数据源执行的.

  • 不知道我能做到这一点,我感到很愚蠢..你刚刚让我免于这么多意大利面条式的代码。 (3认同)

Bry*_*her 20

你可以像你一样继续链接它们.

results = results.Where (o => o.OrderStatus == OrderStatus.Open);
results = results.Where (o => o.InvoicePaid);
Run Code Online (Sandbox Code Playgroud)

这代表一个AND.

  • 重复将where子句添加到查询中,其中包含"and"运算符. (4认同)
  • 有没有办法做到这一点,以便“哪里”是“或”的? (2认同)

Sev*_*ate 7

如果您使用内存数据(读取"POCO集合"),您也可以使用PredicateBuilder将表达式堆叠在一起,如下所示:

// initial "false" condition just to start "OR" clause with
var predicate = PredicateBuilder.False<YourDataClass>();

if (condition1)
{
    predicate = predicate.Or(d => d.SomeStringProperty == "Tom");
}

if (condition2)
{
    predicate = predicate.Or(d => d.SomeStringProperty == "Alex");
}

if (condition3)
{
    predicate = predicate.And(d => d.SomeIntProperty >= 4);
}

return originalCollection.Where<YourDataClass>(predicate.Compile());
Run Code Online (Sandbox Code Playgroud)

提到的完整来源PredicateBuilder是下面的(但您也可以查看原始页面以及更多示例):

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;

public static class PredicateBuilder
{
  public static Expression<Func<T, bool>> True<T> ()  { return f => true;  }
  public static Expression<Func<T, bool>> False<T> () { return f => false; }

  public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> expr1,
                                                      Expression<Func<T, bool>> expr2)
  {
    var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
    return Expression.Lambda<Func<T, bool>>
          (Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters);
  }

  public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
                                                       Expression<Func<T, bool>> expr2)
  {
    var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
    return Expression.Lambda<Func<T, bool>>
          (Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters);
  }
}
Run Code Online (Sandbox Code Playgroud)

注意:我已经使用Portable Class Library项目测试了这种方法,并且必须使用.Compile()它来使它工作:

Where(predicate .Compile());


And*_*tan 6

一定:

if (useAdditionalClauses) 
{ 
  results = 
    results.Where(o => o.OrderStatus == OrderStatus.Open && 
    o.CustomerID == customerID)  
} 
Run Code Online (Sandbox Code Playgroud)

或者只是.Where()像这样的另一个调用(虽然我不知道你为什么想要,除非它被另一个布尔控制变量分割):

if (useAdditionalClauses) 
{ 
  results = results.Where(o => o.OrderStatus == OrderStatus.Open).
    Where(o => o.CustomerID == customerID);
} 
Run Code Online (Sandbox Code Playgroud)

或者另一种重新分配results:`results = results.Where( blah )。