В чем разница между IQueryable и IEnumerable

150

Я смущен относительно разницы. Будучи довольно новым для .Net, я знаю, что могу делать запросы, IEnumerablesиспользуя расширения Linq. Так что же это такое IQueryableи чем оно отличается?


Смотрите также В чем разница между IQueryable [T] и IEnumerable [T]? что совпадает с этим вопросом.

Джеймс Хей
источник

Ответы:

186

IEnumerable<T>представляет курсор только вперед T. В .NET 3.5 добавлены методы расширения, включающие LINQ standard query operatorsподобные Whereи Firstсо всеми операторами, которые требуют предикатов или анонимных функций Func<T>.

IQueryable<T>реализует те же стандартные операторы запросов LINQ, но принимает Expression<Func<T>>предикаты и анонимные функции. Expression<T>является скомпилированным деревом выражений, разбитой версией метода (если хотите, «наполовину скомпилированным»), который может быть проанализирован поставщиком запрашиваемого и использован соответствующим образом.

Например:

IEnumerable<Person> people = GetEnumerablePeople();
Person person = people.Where(x => x.Age > 18).FirstOrDefault();

IQueryable<Person> people = GetQueryablePeople();
Person person = people.Where(x => x.Age > 18).FirstOrDefault();

В первом блоке x => x.Age > 18находится анонимный метод ( Func<Person, bool>), который может быть выполнен как любой другой метод. Enumerable.Whereвыполнит метод один раз для каждого человека, yieldнайдя значения, для которых возвращается метод true.

Во втором блоке x => x.Age > 18находится выражение tree ( Expression<Func<Person, bool>>), которое можно рассматривать как «свойство« Возраст »> 18».

Это позволяет существовать таким вещам, как LINQ-to-SQL, поскольку они могут анализировать дерево выражений и преобразовывать его в эквивалентный SQL. А поскольку провайдеру не нужно выполнять до IQueryableперечисления (в IEnumerable<T>конце концов, он реализует ), он может комбинировать несколько операторов запросов (в приведенном выше примере Whereи FirstOrDefault), чтобы сделать более разумный выбор способов выполнения всего запроса к базовым данным. источник (например, использование SELECT TOP 1в SQL).

Видеть:

Ричард Сзалай
источник
1
довольно краткий ответ
ашвели
83

В реальной жизни, если вы используете ORM, такой как LINQ-to-SQL

  • Если вы создадите IQueryable, запрос может быть преобразован в sql и запущен на сервере базы данных.
  • Если вы создадите IEnumerable, то все строки будут извлечены в память как объекты перед выполнением запроса.

В обоих случаях, если вы не позвоните ToList()или ToArray()запрос будет выполняться каждый раз, когда он будет использоваться, то есть, скажем, у вас есть IQueryableи вы заполняете 4 списка из него, тогда запрос будет выполняться к базе данных 4 раза.

Также, если вы расширяете свой запрос:

q.Select(x.name = "a").ToList()

Затем IQueryableсгенерированный SQL будет содержать where name = "a", но с IEnumerableбольшим количеством ролей будет извлечен из базы данных, тогда x.name = "a"проверка будет выполнена .NET.

Ян Рингроз
источник
«запрос может быть преобразован в sql»: я не получил «может быть». Кроме того, если у меня есть IEnumerable и я создаю «сложную цепочку», то (очевидно) в отличие от IQueryable, он не будет переведен в «оптимизированный» SQL-запрос. Просто хочу подтвердить, что это значит, когда вы говорите «все строки будут перенесены в память». Допустим, у меня есть два предложения where, затем все кортежи сущностей будут сначала извлечены в память, а затем произойдет нормальная фильтрация в памяти?
Вайбхав
36

«Основное отличие состоит в том, что методы расширения, определенные для IQueryable, принимают объекты Expression вместо объектов Func, то есть получаемый им делегат представляет собой дерево выражений, а не метод для вызова. IEnumerable отлично подходит для работы с коллекциями в памяти, но IQueryable позволяет для удаленного источника данных, такого как база данных или веб-служба "

Источник: здесь

Гейб
источник
19

IEnumerable IEnumerable лучше всего подходит для работы с коллекцией в памяти. IEnumerable не перемещается между элементами, он только вперед.

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

Поэтому, когда вам нужно просто перебрать коллекцию в памяти, используйте IEnumerable, если вам нужно выполнить какие-либо манипуляции с коллекцией, такой как набор данных и другие источники данных, используйте IQueryable

Talha
источник
11

Принципиальное отличие состоит в том, что IEnumerable будет перечислять все свои элементы все время, в то время как IQueryable будет перечислять элементы или даже делать другие вещи на основе запроса. Запрос представляет собой выражение (представление данных кода .Net), которое IQueryProvider должен исследовать / интерпретировать / компилировать / как угодно, чтобы генерировать результаты.

Наличие выражения запроса дает два преимущества.

Первое преимущество - это оптимизация. Поскольку такие модификаторы, как «Где», включены в выражение запроса, IQueryProvider может применять невозможные в противном случае оптимизации. Вместо того, чтобы возвращать все элементы, а затем отбрасывать большинство из них из-за предложения «Где», поставщик может использовать хеш-таблицу для поиска элементов с заданным ключом.

Второе преимущество - это гибкость. Поскольку выражения являются структурами данных, которые можно исследовать, вы можете выполнять сериализацию запроса и отправлять его на удаленный компьютер (например, linq-to-sql).

Крейг Гидни
источник
1

IQueriable - это то же самое, что и IEnumerable, но он также предоставляет дополнительные функциональные возможности для реализации пользовательских запросов с Linq. Вот описание на MSDN: http://msdn.microsoft.com/en-us/library/system.linq.iqueryable.aspx

Андрей Беззуб
источник
1

Во-первых, IEnumerable находится в пространстве имен System.Collections, а IQueryable - в пространстве имен System.Linq. Если вы используете IEnumerable при запросе данных из коллекций в памяти, таких как List, Array collection и т. Д. И при запросе данных из коллекций вне памяти (например, удаленная база данных, служба), то вы используете IQueryable. Поскольку при запросе данных из базы данных IEnumerable выполняет запрос на выборку на стороне сервера, загружает данные в память на стороне клиента и затем фильтрует данные. Следовательно делает больше работы и становится медленным. При запросе данных из базы данных IQueryable выполняет запрос выбора на стороне сервера со всеми фильтрами. Следовательно делает меньше работы и становится быстрым.

Найим Мансури
источник