C # LINQ: возвращает ли запрос linq только отложенный перечислимый?

#c# #.net #lambda #.net-core

#c# #.net #лямбда #.net-core

Вопрос:

У меня есть метод

GetPostsByCategory

Я могу сделать это как подход A для повторного использования того, что у меня есть

A

 public IEnumerable<Post> GetPostsByApartmentId(
    string apartmentId,
    int pageIndex,
    int pageSize,
    int max = 50)
{
    var itemsPerPage = Math.Max(pageSize, max);
    return _context.Post
        .Where(p => p.ApartmentId == apartmentId amp;amp; !p.Disabled)
        .Skip((pageIndex - 1) * itemsPerPage)
        .Take(itemsPerPage);
}

public IEnumerable<Post> GetPostsByCategory(
    string categoryId,
    string apartmentId,
    int pageIndex,
    int pageSize,
    int max = 50)
{
    return GetPostsByApartmentId(apartmentId, pageIndex, pageSize, max)
        .Where(p => p.CategoryId == categoryId);
}
  

Но меня беспокоит производительность для A,
итак, вот подход B

 public IEnumerable<Post> GetPostsByCategory(
    string categoryId,
    string apartmentId,
    int pageIndex,
    int pageSize,
    int max)
{
    var itemsPerPage = Math.Max(pageSize, max);
    return _context.Post
        .Where(p => p.ApartmentId == apartmentId amp;amp; !p.Disabled amp;amp; p.CategoryId == categoryId)
        .Skip((pageIndex - 1) * itemsPerPage)
        .Take(itemsPerPage);
}
  

Однако я помню, что читал некоторые статьи, в которых говорилось: лямбда-выражение (или LINQ, не помню) на самом деле не выполняет запрос, оно просто создает запрос и выполняется только тогда, когда это необходимо, или вызывая что-то вроде ToList().
Итак, если это так, то и A, и B должны быть одинаковыми.
Может ли кто-нибудь подтвердить это, пожалуйста?

Комментарии:

1. ericlippert.com/2012/12/17/performance-rant

2. Почему вы беспокоитесь о производительности? Производительность чего именно, дополнительного вызова метода? Вы пробовали измерить разницу?

3. Похоже, вы используете Entity Framework, и возврат IEnumerable материализует результат до этого момента. Ваш актуальный вопрос «Как расширить оператор Where» ?

4. Я думаю, что если вы измените возвращаемый тип GetPostsByApartmentId на IQueryable<Post> , между A и B почти не будет разницы

5. Есть более важный вопрос, который вы должны задать в первую очередь: возвращает ли подход A те же результаты, что и подход B? У меня есть подозрение, что это не так. Медленный код, который выдает правильные результаты, всегда предпочтительнее быстрого кода, который выдает неправильные результаты.

Ответ №1:

Вариант B будет быстрым, поскольку он получает отфильтрованные данные за один раз.

A извлекает все данные на основе условия, а затем фильтрует на основе категории. Существует вероятность того, что в конечном итоге он может получить непреднамеренные данные.

Редактировать:

Было бы интересно в случае хранимой процедуры, как она будет себя вести.

Если у вас есть доступ к profiler, было бы легко проверить, какой оператор final SQL отправляется на sqlserver для выполнения.

Я не очень уверен во внутреннем механизме entity framework.

Но из вашего кода я думаю, что для достижения одной и той же цели компилятор / EF должен сделать что-то за сценой дважды.

Комментарии:

1. Я не думаю, что A извлекает какие-либо данные сам по себе. Он просто возвращает отложенный перечислимый. Данные извлекаются при использовании перечисляемого.

2. спасибо @TheodorZoulias за то, что я прочитал ранее, но я не могу найти ссылку, не могли бы вы, пожалуйста, помочь?

3. @Franva Я мало что знаю о Entity Framework, поэтому я не знаком с его документацией. Я хорошо знаю LINQ для объектов, который ведет себя таким образом.

4. @TheodorZoulias Речь идет о том, что выполняется в базе данных, а что выполняется локально. Подход A извлекает itemsPerPage элементы из базы данных, а затем дополнительно фильтрует их в памяти. Подход B выполняет фильтрацию в базе данных (и прежде чем ограничивать ее itemsPerPage элементами).

5. @Franva это называется отложенным выполнением .