Reputation: 1669
I have a LINQ query that looks like the following:
DateTime today = DateTime.UtcNow;
var results = from order in context.Orders
where ((order.OrderDate <= today) && (today <= order.OrderDate))
select order;
I am trying to learn / understand LINQ. In some cases, I need to add two additional WHERE clauses. In an effort to do this, I'm using:
if (useAdditionalClauses)
{
results = results.Where(o => o.OrderStatus == OrderStatus.Open) // Now I'm stuck.
}
As you can see, I know how to add an additional WHERE clause. But how do I add multiple? For instance, I'd like to add
WHERE o.OrderStatus == OrderStatus.Open AND o.CustomerID == customerID
to my previous query. How do I do this using extension methods?
Thank you!
Upvotes: 98
Views: 185838
Reputation: 17307
Just use the &&
operator like you would with any other statement that you need to do boolean logic.
if (useAdditionalClauses)
{
results = results.Where(
o => o.OrderStatus == OrderStatus.Open
&& o.CustomerID == customerID)
}
Upvotes: 0
Reputation: 6475
If you working with in-memory data (read "collections of POCO") you may also stack your expressions together using PredicateBuilder like so:
// 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());
The full source of mentioned PredicateBuilder
is bellow (but you could also check the original page with a few more examples):
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);
}
}
Note: I've tested this approach with Portable Class Library project and have to use .Compile()
to make it work:
Where(predicate .Compile() );
Upvotes: 19
Reputation: 2685
results = context.Orders.Where(o => o.OrderDate <= today && today <= o.OrderDate)
The select is uneeded as you are already working with an order.
Upvotes: 1
Reputation: 4363
you can use && and write all conditions in to the same where clause, or you can .Where().Where().Where()... and so on.
Upvotes: 2
Reputation: 218847
Two ways:
results = results.Where(o => (o.OrderStatus == OrderStatus.Open) &&
(o.CustomerID == customerID));
or:
results = results.Where(o => (o.OrderStatus == OrderStatus.Open))
.Where(o => (o.CustomerID == customerID));
I usually prefer the latter. But it's worth profiling the SQL server to check the query execution and see which one performs better for your data (if there's any difference at all).
A note about chaining the .Where()
methods: You can chain together all the LINQ methods you want. Methods like .Where()
don't actually execute against the database (yet). They defer execution until the actual results are calculated (such as with a .Count()
or a .ToList()
). So, as you chain together multiple methods (more calls to .Where()
, maybe an .OrderBy()
or something to that effect, etc.) they build up what's called an expression tree. This entire tree is what gets executed against the data source when the time comes to evaluate it.
Upvotes: 188
Reputation: 4535
You can continue chaining them like you've done.
results = results.Where (o => o.OrderStatus == OrderStatus.Open);
results = results.Where (o => o.InvoicePaid);
This represents an AND.
Upvotes: 29
Reputation: 42353
Surely:
if (useAdditionalClauses)
{
results =
results.Where(o => o.OrderStatus == OrderStatus.Open &&
o.CustomerID == customerID)
}
Or just another .Where()
call like this one (although I don't know why you would want to, unless it's split by another boolean control variable):
if (useAdditionalClauses)
{
results = results.Where(o => o.OrderStatus == OrderStatus.Open).
Where(o => o.CustomerID == customerID);
}
Or another reassignment to results
: `results = results.Where(blah).
Upvotes: 6