Несколько предложений WHERE с использованием методов расширения LINQ
У меня есть запрос 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
к моему предыдущему запросу. Как это сделать с помощью методов расширения?
Спасибо!
Ответы
Ответ 1
Два способа:
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()
или что-то в этом роде и т.д.), Они создают то, что называется деревом выражений . Это все дерево - это то, что выполняется против источника данных, когда придет время его оценить.
Ответ 2
Вы можете продолжить цепочку, как вы это сделали.
results = results.Where (o => o.OrderStatus == OrderStatus.Open);
results = results.Where (o => o.InvoicePaid);
Это представляет собой AND.
Ответ 3
Если вы работаете с данными в памяти (читайте "коллекции 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 Class Library и должен использовать .Compile()
для заставить его работать:
Где (предикат .Compile());
Ответ 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).
Ответ 5
вы можете использовать && и записывать все условия в том же самом разделе where, или вы можете .Where(). Where(). Where()... и т.д.
Ответ 6
results = context.Orders.Where(o => o.OrderDate <= today && today <= o.OrderDate)
Выбирается, если вы уже работаете с заказом.
Ответ 7
Просто используйте оператор &&
, как и любой другой оператор, который вам нужен для логической логики.
if (useAdditionalClauses)
{
results = results.Where(
o => o.OrderStatus == OrderStatus.Open
&& o.CustomerID == customerID)
}