В чем разница между IQueryable <T> и IEnumerable <T>?


Ответы:


258

Прежде всего, распространяется на интерфейс, так что вы можете сделать с «простой» , вы также можете сделать с .IQueryable<T> IEnumerable<T>IEnumerable<T>IQueryable<T>

IEnumerable<T>просто есть GetEnumerator()метод , который возвращает , Enumerator<T>для которого вы можете вызвать его MoveNext()метод перебора последовательности T .

Что IQueryable<T>еще , что IEnumerable<T> не два свойства , в частности , один год, что указывает на поставщика запроса (например, LINQ к провайдеру SQL) и еще один , указывающий на выражение запроса , представляющий IQueryable<T>объект , как на этапе выполнения проходимой абстрактного синтаксического дерева , которое может быть понимается данным поставщиком запросов (по большей части вы не можете передать выражение LINQ to SQL поставщику LINQ to Entities без исключения).

Выражение может быть просто константным выражением самого объекта или более сложным деревом составленного набора операторов и операндов запроса. Поставщик запроса IQueryProvider.Execute()или IQueryProvider.CreateQuery()методы вызываются с переданным ему выражением , а затем IQueryableвозвращается либо результат запроса, либо другой , соответственно.


8
Есть ли польза от использования AsQueryable?
Иордания

6
Единственное преимущество - удобство. AsQueryable()просто приведёт перечислимое к запрашиваемому и вернет его, если он реализует IQueryableинтерфейс, в противном случае он оборачивает его в объект ConstantExpression, на который ссылается возвращаемый EnumerableQueryобъект.
Марк Сидаде


1
Стоит прочитать эту статью
JenonD

Ссылка @JenonD мертва, вот обратная машина: web.archive.org/web/20160904162931/http://www.dotnet-tricks.com/…
Маджам

201

Основное отличие состоит в том, что операторы LINQ для объектов IQueryable<T>take Expressionвместо делегатов, что означает, что полученная пользователем логика запроса, например, предикат или селектор значения, имеет форму дерева выражений, а не делегата метода.

  • IEnumerable<T> отлично подходит для работы с последовательностями, которые повторяются в памяти, но
  • IQueryable<T> позволяет использовать нехватку памяти, например, удаленный источник данных, например базу данных или веб-сервис.

Выполнение запроса:

  • Там, где выполнение запроса будет выполняться «в процессе» , обычно все, что требуется, - это код (как код) для выполнения каждой части запроса.

  • Если выполнение будет выполняться вне процесса , логика запроса должна быть представлена ​​в данных таким образом, чтобы поставщик LINQ мог преобразовать его в соответствующую форму для выполнения из нехватки памяти - будь то запрос LDAP, SQL или что-то еще.

Больше:

http://www.codeproject.com/KB/cs/646361/WhatHowWhere.jpg


14
Мне нравится упоминание об операциях вне памяти. Выясняется реальная практическая разница в использовании.
Измаил Смирноу

2
Вместо того, чтобы принимать делегаты в качестве параметров, таких как метод IEnumerable <T> Where, IQueryable <T> будет принимать параметры Expression <TDelegate>. Мы не передаем код в IQueryable <T>, мы передаем деревья выражений (код как данные) для анализа поставщиком LINQ. C # 3.0 и LINQ
Lu55

что-то не так с вашей ссылкой на изображение, по какой-то причине оно не отображается в теле сообщения codeproject.com/KB/cs/646361/WhatHowWhere.jpg
jbooker

@joey Тем не менее, я вижу это изображение очень хорошо в этом ответе: i.stack.imgur.com/2DAqv.jpg
VonC

190

Это хорошее видео на YouTube, которое демонстрирует, как эти интерфейсы отличаются, стоит посмотреть.

Ниже приводится длинный описательный ответ.

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

введите описание изображения здесь

Есть много различий, но давайте поговорим об одной большой разнице, которая имеет самое большое значение. IEnumerableИнтерфейс полезен, когда ваша коллекция загружается с использованием LINQили Entity Framework, и вы хотите применить фильтр к коллекции.

Рассмотрим приведенный ниже простой код, который используется IEnumerableсо структурой сущности. Он с помощью Whereфильтра , чтобы получить записи , у которых EmpIdесть 2.

EmpEntities ent = new EmpEntities();
IEnumerable<Employee> emp = ent.Employees; 
IEnumerable<Employee> temp = emp.Where(x => x.Empid == 2).ToList<Employee>();

Это где фильтр выполняется на стороне клиента, где IEnumerableкод. Другими словами, все данные извлекаются из базы данных, а затем на клиенте сканируются и получают запись с EmpIdis 2.

введите описание изображения здесь

Но теперь увидеть ниже код , который мы изменили IEnumerableна IQueryable. Он создает SQL-запрос на стороне сервера, а на стороне клиента отправляются только необходимые данные.

EmpEntities ent = new EmpEntities();
IQueryable<Employee> emp = ent.Employees;
IQueryable<Employee> temp =  emp.Where(x => x.Empid == 2).ToList<Employee>();

введите описание изображения здесь

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

Поэтому, если вы работаете только со сбором данных в памяти IEnumerable, это хороший выбор, но если вы хотите запросить сбор данных, связанный с базой данных, IQueryable - лучший выбор, поскольку он уменьшает сетевой трафик и использует мощь языка SQL.


Привет, большое спасибо за прекрасное объяснение. Я понимаю, почему IQueryable является лучшим выбором для данных «вне памяти», но я пытаюсь понять, почему IEnumerable лучше для данных «в памяти»? Я все еще думаю, что лучше получить отфильтрованные данные, чем получить данные и применить фильтр.
Имад

когда это «в памяти», это не имеет значения. данные уже находятся в памяти, в какое точное время они фильтруются, не имеет значения.
Рони Аксельрад

@Imad Например, проецирование данных путем преобразования сущности DateTimeOffset в DateTime невозможно с помощью IQueryable или EntityFunctions. Наилучший способ состоит в том, чтобы AsEnumerable () объект сущности, затем Select () в viewmodel, который содержит DateTime. Этот процесс использует функции в памяти.
Джефф

57

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

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

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


3
Разве IEnumerable не использует отложенное выполнение?
Ян Уорбертон

3
Отложенное выполнение доступно как в IEnumerable, так и в IQueryable. Дополнительная интересная информация может быть найдена здесь: stackoverflow.com/questions/2876616/…
Игнасио Хагопиан,

18

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


17

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

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

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

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

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

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


10

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


9

Приведенный ниже небольшой тест может помочь вам понять один аспект различия между IQueryable<T>и IEnumerable<T>. Я воспроизвел этот ответ из этого поста, где я пытался добавить исправления в чужой пост

Я создал следующую структуру в БД (скрипт DDL):

CREATE TABLE [dbo].[Employee]([PersonId] [int] NOT NULL PRIMARY KEY,[Salary] [int] NOT NULL)

Вот скрипт вставки записи (DML скрипт):

INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(1, 20)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(2, 30)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(3, 40)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(4, 50)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(5, 60)
GO

Теперь моя цель состояла в том, чтобы просто получить две лучшие записи из Employeeтаблицы в базе данных. Я добавил в консольное приложение элемент ADO.NET Entity Data Model, указывающий на Employeeтаблицу в моей базе данных, и начал писать запросы LINQ.

Код для IQueryable маршрута :

using (var efContext = new EfTestEntities())
{
    IQueryable<int> employees = from e in efContext.Employees  select e.Salary;
    employees = employees.Take(2);

    foreach (var item in employees)
    {
        Console.WriteLine(item);
    }
}

Когда я начал запускать эту программу, я также запустил сеанс профилировщика SQL-запросов на своем экземпляре SQL Server, и вот краткая информация о выполнении:

  1. Общее количество выполненных запросов: 1
  2. Текст запроса: SELECT TOP (2) [c].[Salary] AS [Salary] FROM [dbo].[Employee] AS [c]

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

Код для IEnumerable маршрута :

using (var efContext = new EfTestEntities())
{
    IEnumerable<int> employees = from e in efContext.Employees  select e.Salary;
    employees = employees.Take(2);

    foreach (var item in employees)
    {
        Console.WriteLine(item);
    }
}

Резюме выполнения в этом случае:

  1. Общее количество выполненных запросов: 1
  2. Текст запроса, захваченный в профилировщике SQL: SELECT [Extent1].[Salary] AS [Salary] FROM [dbo].[Employee] AS [Extent1]

Теперь IEnumerableвсе 5 записей, представленных в Salaryтаблице, затем подвергли фильтрации в оперативной памяти на клиентском компьютере, чтобы получить две верхние записи. Таким образом, больше данных (в данном случае 3 дополнительных записи) были переданы по проводам без необходимости.


7

Вот что я написал в аналогичном посте (по этой теме). (И нет, я обычно не цитирую себя, но это очень хорошие статьи.)

«Эта статья полезна: IQueryable против IEnumerable в LINQ-to-SQL .

Цитируя эту статью: «Согласно документации MSDN, вызовы, выполняемые в IQueryable, работают вместо этого путем построения внутреннего дерева выражений. «Эти методы, расширяющие IQueryable (Of T), не выполняют никаких запросов напрямую. Вместо этого их функциональность заключается в создании объекта Expression, который представляет собой дерево выражений, представляющее совокупный запрос».

Деревья выражений являются очень важной конструкцией в C # и на платформе .NET. (В целом они важны, но C # делает их очень полезными.) Чтобы лучше понять разницу, я рекомендую прочитать о различиях между выражениями и утверждениями в официальной спецификации C # 5.0 здесь. Для продвинутых теоретических концепций, которые переходят в лямбда-исчисление, выражения включают поддержку методов как первоклассных объектов. Разница между IQueryable и IEnumerable сосредоточена вокруг этой точки. IQueryable создает деревья выражений, а IEnumerable - нет, по крайней мере, в общих чертах для тех из нас, кто не работает в секретных лабораториях Microsoft.

Вот еще одна очень полезная статья, которая детализирует различия с точки зрения толчка против толчка. (Под «push» против «pull» я имею в виду направление потока данных. Методы реактивного программирования для .NET и C #

Вот очень хорошая статья, которая детализирует различия между лямбда-выражениями операторов и лямбда-выражениями и более детально обсуждает концепции выражения tress: Пересмотр делегатов C #, деревьев выражений и лямбда-операторов по сравнению с лямбда-выражениями. «.


6

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

Найти более подробное разграничение ниже:

IEnumerable

  1. IEnumerableсуществует в System.Collectionsпространстве имен
  2. IEnumerable выполнить запрос выбора на стороне сервера, загрузить данные в память на стороне клиента и затем отфильтровать данные
  3. IEnumerable подходит для запроса данных из коллекций в памяти, таких как List, Array
  4. IEnumerable выгодно для запросов LINQ to Object и LINQ to XML

IQueryable

  1. IQueryableсуществует в System.Linqпространстве имен
  2. IQueryable выполняет «запрос на выборку» на стороне сервера со всеми фильтрами
  3. IQueryable подходит для запроса данных из нехватки памяти (например, удаленной базы данных, службы)
  4. IQueryable полезно для LINQ to SQL запросов

Так IEnumerableобычно используется для работы с коллекциями в памяти, тогда как IQueryableобычно используется для манипулирования коллекциями.


3

И IEnumerable, и IQueryable используются для хранения коллекции данных и выполнения операции манипулирования данными, например, фильтрации коллекции данных. Здесь вы можете найти лучшее сравнение различий с примером. http://www.gurujipoint.com/2017/05/difference-between-ienumerable-and.html введите описание изображения здесь


2

IQueryable работает быстрее, чем IEnumerable, если мы имеем дело с огромными объемами данных из базы данных, поскольку IQueryable получает только необходимые данные из базы данных, а IEnumerable получает все данные независимо от необходимости из базы данных.


0

ienumerable: когда мы хотим иметь дело с оперативной памятью, то есть без подключения к данным; iqueryable: когда иметь дело с сервером sql, то есть с подключением к данным. ilist: операции, такие как добавление объекта, удаление объекта и т. д.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.