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

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

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

谢谢!

两种方式:

 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()或类似的东西.OrderBy()等),他们build立了所谓的expression树 。 整个树就是在评估数据源的时候执行的。

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

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

这代表一个AND。

如果你使用内存数据(读取“POCO的集合”),你也可以使用PredicateBuilder将你的expression式堆叠在一起,像这样:

 // 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 Class Library项目testing了这种方法,并且必须使用.Compile()使其工作:

Where(predicate .Compile() );

一定:

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

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

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

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

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

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

由于您已经在处理订单,因此select不受欢迎。

只要使用&&操作符就像使用其他需要执行布尔逻辑的语句一样。

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