Несколько предложений 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

к моему предыдущему запросу. Как это сделать с помощью расширения методы?

спасибо!

7 58

7 ответов:

два варианта:

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 server, чтобы проверить выполнение запроса и посмотреть, какой из них лучше работает для ваших данных (если есть какая-либо разница вообще).

примечание о цепочке .Where() методы: вы можете связать вместе все методы LINQ, которые вы хотите. Такие методы, как .Where() на самом деле не выполняется против базы данных (пока). Они отложить исполнение пока фактические результаты вычисляются (например, с помощью .Count() или .ToList()). Итак, как вы цепочку вместе несколько методов (больше вызовов .Where(), возможно .OrderBy() или что-то в этом роде, и т. д.) они создают то, что называется выражение дерево. Все это дерево является то, что выполняется в источнике данных, когда приходит время, чтобы оценить его.

вы можете продолжать цепочку их, как вы сделали.

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

это представляет собой и.

если вы работаете с данными в памяти (читайте "коллекции 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);
  }
}

Примечание: я проверил этот подход с Переносимая Библиотека Классов и .Compile() сделать это работа:

где(предикат .Компилировать() );

обязательно:

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);
} 

или другое переназначение на : ` = результаты.Где (мля).

вы можете использовать && и записать все условия в том же предложении where, или вы можете .Где.)(Где.)(Где.)(.. и так далее.

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

выбор не требуется, так как вы уже работаете с заказом.

просто использовать && оператор, как вы бы с любым другим утверждением,что вам нужно сделать логическую логику.

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