Я неправильно понимаю LINQ to SQL .AsEnumerable ()? - PullRequest
45 голосов
/ 02 августа 2010

Рассмотрим этот код:

var query = db.Table
              .Where(t => SomeCondition(t))
              .AsEnumerable();

int recordCount = query.Count();
int totalSomeNumber = query.Sum();
decimal average = query.Average();

Предположим, query занимает очень много времени для запуска.Мне нужно получить количество записей, общее количество возвращенных SomeNumber и взять среднее значение в конце.Исходя из моего чтения, я подумал, что .AsEnumerable() выполнит запрос с использованием LINQ-to-SQL, а затем использует LINQ-to-Objects для Count, Sum и Average.Вместо этого, когда я делаю это в LINQPad, я вижу, что один и тот же запрос выполняется три раза.Если я заменю .AsEnumerable() на .ToList(), он будет запрошен только один раз.

Я что-то упускаю из-за того, что AsEnumerable есть / делает?

Ответы [ 5 ]

57 голосов
/ 02 августа 2010

Вызов AsEnumerable() не выполняет запрос, перечисляя его.

IQueryable - это интерфейс, который позволяет LINQ to SQL выполнять свою магию. IQueryable реализует IEnumerable, поэтому, когда вы вызываете AsEnumerable(), вы меняете методы расширения, которые вызываются с этого момента, то есть с IQueryable -методов на IEnumerable -методов (то есть с LINQ to SQL до LINQ to Objects в данном конкретном случае). Но вы не выполняете фактический запрос, просто меняете способ его выполнения в полном объеме.

Чтобы принудительно выполнить запрос, вы должны вызвать ToList().

14 голосов
/ 02 августа 2010

Да.Все, что сделает AsEnumerable, это заставит функции Count, Sum и Average выполняться на стороне клиента (другими словами, он вернет весь набор результатов клиенту, тогда клиент будетвыполнять эти агрегаты вместо создания операторов COUNT() SUM() и AVG() в SQL).

4 голосов
/ 02 августа 2010

Ну, вы на правильном пути.Проблема состоит в том, что IQueryable (то, что является оператором перед вызовом AsEnumerable) также является IEnumerable, так что этот вызов, по сути, nop.Для принудительного выполнения запроса потребуется принудительная привязка к определенной структуре данных в памяти (например, ToList()).

3 голосов
/ 07 июня 2017

ответ Джастина Нисснера идеально.

Я просто хочу процитировать MSDN здесь: .NET-встроенный запрос для реляционных данных

Оператор AsEnumerable (), в отличие от ToList () и ToArray (), не вызывает выполнения запроса. Это все еще отложено. Оператор AsEnumerable () просто изменяет статическую типизацию запроса, превращая IQueryable в IEnumerable, заставляя компилятор трактовать оставшуюся часть запроса как выполненную локально.

Надеюсь, это то, что подразумевается под:

IQueryable-методы для IEnumerable-методов (т. Е. Переход с LINQ на SQL на LINQ для объектов

Когда это LINQ к объектам, мы можем применять методы объекта (например, ToString () ). Это объяснение одного из часто задаваемых вопросов о LINQ - Почему LINQ to Entities не распознает метод 'System.String ToString ()?

Согласно ASENUMERABLE - codeblog.jonskeet , AsEnumerable может пригодиться, когда:

некоторые аспекты запроса в базе данных, а затем немного больше манипуляций в .NET - особенно если есть аспекты, которые вы в принципе не можете реализовать в LINQ to SQL (или любого другого поставщика, которого вы используете).

Там также написано:

Все, что мы делаем, - это изменяем тип времени компиляции последовательности, которая распространяется через наш запрос, с IQueryable на IEnumerable, но это означает, что компилятор будет использовать методы в Enumerable (принимая делегаты и выполняя в LINQ Объекты) вместо объектов в Queryable (с использованием деревьев выражений и, как правило, выполнением вне процесса).

Наконец, также см. Этот связанный вопрос: Возвращение IEnumerable vs. IQueryable

1 голос
/ 02 августа 2010

Я бы предположил, что ToList заставляет Linq извлекать записи из базы данных. Когда вы затем выполняете текущие вычисления, они выполняются с объектами в памяти, а не с базой данных.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...