使用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) }