我有一个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
到我之前的查询。如何使用扩展方法执行此操作?
谢谢!
答案 0 :(得分:124)
两种方式:
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()
这样的方法实际上并没有针对数据库执行。他们defer execution直到计算出实际结果(例如使用.Count()
或.ToList()
)。因此,当您将多个方法(对.Where()
的更多调用,可能是.OrderBy()
或其他类似的调用等)链接在一起时,它们会构建所谓的expression tree。这个整个树是在评估它时对数据源执行的。
答案 1 :(得分:18)
你可以像你一样继续链接它们。
results = results.Where (o => o.OrderStatus == OrderStatus.Open);
results = results.Where (o => o.InvoicePaid);
这代表一个AND。
答案 2 :(得分:7)
如果您使用内存数据(阅读&#34; POCO&#34;的集合),您也可以使用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
的完整来源如下(但您还可以查看original page以及更多示例):
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项目对此方法进行了测试,并且必须使用.Compile()
才能使其正常运行:
其中(谓词 .Compile());
答案 3 :(得分:4)
当然:
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 )。
答案 4 :(得分:2)
你可以使用&amp;&amp;并将所有条件写入相同的where子句,或者你可以.Where()。Where()。Where()...等等。
答案 5 :(得分:1)
results = context.Orders.Where(o => o.OrderDate <= today && today <= o.OrderDate)
由于您已经在处理订单,因此无法选择。
答案 6 :(得分:0)
只需使用&&
运算符,就像使用布尔逻辑所需的任何其他语句一样。
if (useAdditionalClauses)
{
results = results.Where(
o => o.OrderStatus == OrderStatus.Open
&& o.CustomerID == customerID)
}