具有LINQ扩展方法的多个WHERE子句


79

我有一个看起来像下面的LINQ查询:

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

我正在尝试学习/理解LINQ。在某些情况下,我需要添加两个附加的WHERE子句。为了做到这一点,我正在使用:

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

如您所见,我知道如何添加其他WHERE子句。但是如何添加多个?例如,我想添加

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

到我以前的查询。如何使用扩展方法做到这一点?

谢谢!

Answers:


151

两种方式:

results = results.Where(o => (o.OrderStatus == OrderStatus.Open) &&
                             (o.CustomerID == customerID));

要么:

results = results.Where(o => (o.OrderStatus == OrderStatus.Open))
                 .Where(o => (o.CustomerID == customerID));

我通常更喜欢后者。但是值得对SQL Server进行性能分析,以检查查询的执行情况,并查看哪一个对您的数据性能更好(如果有任何区别)。

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


2
我不知道自己能做到这一点而感到愚蠢。
ledgeJumper 2014年

谢谢,这对我有帮助。但是我是否也有可能会根据某个变量触发任何一个where子句?@David
Muhammad Ashikuzzaman 2015年

您可以在最后使用select子句吗?

@New_Coder:当然可以。.Where()子句不会更改返回类型。
David

它很奇怪,因为当我这样做时:List <string>路径= db.ClientStatement_Inventory .Where(x =>(x.statementYear ==是)).Where(x =>(x.statementMonth == mon)).Select( c => c.statementPath).ToList(); 没用 但是如果我只有1个where子句,它将查询我的数据库。

24

您可以像完成操作一样继续链接它们。

results = results.Where (o => o.OrderStatus == OrderStatus.Open);
results = results.Where (o => o.InvoicePaid);

这代表一个AND。


您(和其他人)也击败了我,但这可能是最易读的方式。
Schroedingers Cat 2012年

4
重复将where子句添加到查询中,中间使用“和”运算符。
linkerro 2012年

这可能不是“最干净”的解决方案,但就我而言,这是迄今为止唯一可行的解​​决方案。我必须根据UI中的选择添加“ where”子句。
DJ van Wyk

1
有没有一种方法可以做到“或”在哪里?
EK_AllDay

11

如果您使用内存中的数据(请阅读“ 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());

提到的完整来源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);
  }
}

注意:我已经在可移植类库项目中测试了这种方法,并且必须使用.Compile()它来使其工作:

Where(谓词.Compile());


有什么原因不能与Entity Framework LINQ一起使用吗?
Ciantic

我也可以与EF Core搭配使用。结果谓词已正确转换为SQL。
托马斯·希尔伯特

5

一定:

if (useAdditionalClauses) 
{ 
  results = 
    results.Where(o => o.OrderStatus == OrderStatus.Open && 
    o.CustomerID == customerID)  
} 

或者只是这样的另一个.Where()调用(尽管我不知道您为什么要这么做,除非它被另一个布尔控制变量分开):

if (useAdditionalClauses) 
{ 
  results = results.Where(o => o.OrderStatus == OrderStatus.Open).
    Where(o => o.CustomerID == customerID);
} 

或重新分配给results:`results = results.Where(blah)。


2

您可以使用&&并将所有条件写入相同的where子句中,也可以使用.Where()。Where()。Where()...等。


1
results = context.Orders.Where(o => o.OrderDate <= today && today <= o.OrderDate)

由于您已经在处理订单,因此该选择没有设置。


0

只需将&&运算符与需要执行布尔逻辑的任何其他语句一样使用即可。

if (useAdditionalClauses)
{
  results = results.Where(
                  o => o.OrderStatus == OrderStatus.Open 
                  && o.CustomerID == customerID)     
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.