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

本文关键字:WHERE 子句 LINQ 扩展 方法 具有 | 更新日期: 2023-09-27 18:19:46

我有一个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

回复我之前的查询。如何使用扩展方法来完成此操作?

谢谢!

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

两种方式:

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服务器进行分析是值得的,以检查查询执行情况,并查看哪一个查询对您的数据表现更好(如果有任何差异的话)。

关于链接.Where()方法的注意事项:您可以将所需的所有LINQ方法链接在一起。像.Where()这样的方法实际上还没有针对数据库执行。它们推迟执行,直到计算出实际结果(例如使用.Count().ToList())。因此,当你将多个方法(更多地调用.Where(),可能是.OrderBy()或类似的东西,等等)链接在一起时,它们会构建一个所谓的表达式树。这整棵树是在评估数据源时对其执行的。

您可以像以前那样继续链接它们。

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

这表示AND。

如果您使用内存中的数据(读取"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);
  }
}

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

其中(谓词.Compile());

当然:

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。其中(等等)。

您可以使用&amp;并将所有条件写入同一个where子句,或者可以。where()。where

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

选择是非种子的,因为您已经在处理订单了。

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

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