LINQ to Entities - OrderBy().ToLisT() или ToList().OrderBy()

Я ищу подтверждение / уточнение с этими выражениями LINQ:

var context = new SomeCustomDbContext()

// LINQ to Entities?
var items  = context.CustomItems.OrderBy(i => i.Property).ToList();

// LINQ to Objects?
var items2 = context.CustomItems.ToList().OrderBy(i => i.Property);

(Q1) Правильно ли я считаю, что первый метод LINQ to Entities где EF создает более конкретный оператор SQL для передачи, упорядочивая базу данных?

(Q2) это второй метод LINQ to Objects где LINQ перетаскивает всю коллекцию в память (ToList() перечисление?) перед заказом, таким образом, оставляя бремя на стороне сервера (веб-сервер в данном случае)?

Если это так, я могу быстро увидеть ситуации, в которых L2E был бы выгоден (например, фильтрация / обрезка коллекций перед вытягиванием их в память).

(Q3) Но есть ли какие-либо другие детали / компромиссы, о которых я должен знать, или времена, когда "метод 2" может быть выгоднее первого метода?

ОБНОВИТЬ:

Допустим, мы не используем EntityFramework, это все еще верно, пока базовый репозиторий / источник данных реализует IQueryable<T> право? И если это не так, оба эти заявления приводят к LINQ to Objects операции в памяти?

3 ответа

Решение
  1. Да.
  2. Да.
  3. Да.

Вы правы в том, что зовете ToList() заставляет linq-to-entity оценивать и возвращать результаты в виде списка. Как вы подозреваете, это может иметь огромное влияние на производительность.

Есть случаи, когда linq-to-entity не может понять, как анализировать то, что выглядит как совершенно простой запрос (например, Where(x => SomeFunction(x))). В этих случаях у вас часто нет другого выбора, кроме как позвонить ToList() и оперировать коллекцией в памяти.


В ответ на ваше обновление:

ToList() всегда заставляет все, что впереди, оценивать немедленно, в отличие от отложенного исполнения. Возьмите этот пример:

someEnumerable.Take(10).ToList();

против

someEnumerable.ToList().Take(10);

Во втором примере любая отложенная работа на someEnumerable должен быть выполнен перед тем, как взять первые 10 элементов. Если someEnumerable делает что-то трудоемкое (например, чтение файлов с диска с помощью Directory.EnumerateFiles()), это может иметь очень реальные последствия для производительности.

Правильно ли я считаю, что первый метод - это LINQ to Entities, где EF создает более конкретный оператор SQL для передачи, упорядочивая базу данных?

да

Является ли второй метод LINQ to Objects, где LINQ перетаскивает всю коллекцию в память... перед упорядочением, оставляя бремя на стороне сервера...?

да

Но есть ли какие-либо другие детали / компромиссы, о которых я должен знать, или случаи, когда "метод 2" может быть выгоднее первого метода?

Во многих случаях метод 1 будет невозможен - обычно, когда у вас есть сложный фильтр или порядок сортировки, который не может быть напрямую переведен в SQL (или более уместно, когда EF не поддерживает прямую трансляцию SQL). Кроме того, так как вы не можете передавать лениво загружен IQueryables по проводам, каждый раз, когда вам нужно сериализовать результат, вы должны сначала его материализовать ToList() или что-то подобное.

Еще одна вещь, о которой следует знать, - это то, что IQueryable не дает никаких гарантий ни (а) о семантических рассуждениях базового поставщика, либо (b) о том, какая часть набора методов IQueryable реализована поставщиком.

Например: -

  1. EF не поддерживает Last().
  2. Он также не поддерживает сравнение временных дат DateTimes с действительным T-SQL.
  3. Он не поддерживает FirstOrDefault() в подзапросах.

В таких обстоятельствах вам необходимо вернуть данные клиенту, а затем выполнить дальнейшую оценку на стороне клиента.

Вам также необходимо иметь представление о том, "как" он анализирует конвейер LINQ для генерации (в случае EF) T-SQL. Поэтому иногда вам нужно тщательно продумать, как вы строите свои запросы LINQ, чтобы генерировать эффективный T-SQL.

Тем не менее, IQueryable<> является чрезвычайно мощным инструментом в среде.NET, и с ним стоит познакомиться поближе.

Другие вопросы по тегам