В чем разница между IQueryable<T>
и IEnumerable<T>
?
Смотрите также В чем разница между IQueryable и IEnumerable, который перекрывается с этим вопросом.
В чем разница между IQueryable<T>
и IEnumerable<T>
?
Смотрите также В чем разница между IQueryable и IEnumerable, который перекрывается с этим вопросом.
Ответы:
Прежде всего, распространяется на интерфейс, так что вы можете сделать с «простой» , вы также можете сделать с .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
возвращается либо результат запроса, либо другой , соответственно.
AsQueryable()
просто приведёт перечислимое к запрашиваемому и вернет его, если он реализует IQueryable
интерфейс, в противном случае он оборачивает его в объект ConstantExpression
, на который ссылается возвращаемый EnumerableQuery
объект.
Основное отличие состоит в том, что операторы LINQ для объектов IQueryable<T>
take Expression
вместо делегатов, что означает, что полученная пользователем логика запроса, например, предикат или селектор значения, имеет форму дерева выражений, а не делегата метода.
IEnumerable<T>
отлично подходит для работы с последовательностями, которые повторяются в памяти, но IQueryable<T>
позволяет использовать нехватку памяти, например, удаленный источник данных, например базу данных или веб-сервис.Там, где выполнение запроса будет выполняться «в процессе» , обычно все, что требуется, - это код (как код) для выполнения каждой части запроса.
Если выполнение будет выполняться вне процесса , логика запроса должна быть представлена в данных таким образом, чтобы поставщик LINQ мог преобразовать его в соответствующую форму для выполнения из нехватки памяти - будь то запрос LDAP, SQL или что-то еще.
Больше:
Это хорошее видео на 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
код. Другими словами, все данные извлекаются из базы данных, а затем на клиенте сканируются и получают запись с EmpId
is 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.
IEnumerable: IEnumerable лучше всего подходит для работы с коллекцией в памяти (или локальными запросами). IEnumerable не перемещается между элементами, он только вперед.
IQueryable: IQueryable лучше всего подходит для удаленного источника данных, такого как база данных или веб-служба (или удаленные запросы). IQueryable - это очень мощная функция, которая позволяет использовать множество интересных сценариев отложенного выполнения (таких как запросы на пейджинг и на основе композиции).
Поэтому, когда вам нужно просто перебрать коллекцию в памяти, используйте IEnumerable, если вам нужно выполнить какие-либо манипуляции с коллекцией, такой как набор данных и другие источники данных, используйте IQueryable
В реальной жизни, если вы используете ORM, такой как LINQ-to-SQL
В обоих случаях, если вы не вызываете ToList()
или ToArray()
запрос будет выполняться каждый раз, когда он будет использоваться, например, у вас есть IQueryable<T>
и вы заполняете 4 списка из него, тогда запрос будет выполняться к базе данных 4 раза.
Также, если вы расширяете свой запрос:
q.Where(x.name = "a").ToList()
Затем с IQueryable сгенерированный SQL будет содержать «где name =« a », но с IEnumerable из базы данных будет извлечено гораздо больше ролей, затем .NET выполнит проверку x.name =« a ».
Приведенный ниже небольшой тест может помочь вам понять один аспект различия между 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, и вот краткая информация о выполнении:
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);
}
}
Резюме выполнения в этом случае:
SELECT [Extent1].[Salary] AS [Salary]
FROM [dbo].[Employee] AS [Extent1]
Теперь IEnumerable
все 5 записей, представленных в Salary
таблице, затем подвергли фильтрации в оперативной памяти на клиентском компьютере, чтобы получить две верхние записи. Таким образом, больше данных (в данном случае 3 дополнительных записи) были переданы по проводам без необходимости.
Вот что я написал в аналогичном посте (по этой теме). (И нет, я обычно не цитирую себя, но это очень хорошие статьи.)
«Эта статья полезна: 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 #, деревьев выражений и лямбда-операторов по сравнению с лямбда-выражениями. «.
Мы используем IEnumerable
и IQueryable
для манипулирования данными, полученными из базы данных. IQueryable
наследует IEnumerable
, поэтому IQueryable
содержит все IEnumerable
функции. Основное различие между IQueryable
и IEnumerable
заключается в том, что IQueryable
выполняется запрос с фильтрами, тогда IEnumerable
как сначала выполняется запрос, а затем он фильтрует данные на основе условий.
Найти более подробное разграничение ниже:
IEnumerable
IEnumerable
существует в System.Collections
пространстве именIEnumerable
выполнить запрос выбора на стороне сервера, загрузить данные в память на стороне клиента и затем отфильтровать данныеIEnumerable
подходит для запроса данных из коллекций в памяти, таких как List, ArrayIEnumerable
выгодно для запросов LINQ to Object и LINQ to XMLIQueryable
IQueryable
существует в System.Linq
пространстве именIQueryable
выполняет «запрос на выборку» на стороне сервера со всеми фильтрамиIQueryable
подходит для запроса данных из нехватки памяти (например, удаленной базы данных, службы)IQueryable
полезно для LINQ to SQL запросовТак IEnumerable
обычно используется для работы с коллекциями в памяти, тогда как IQueryable
обычно используется для манипулирования коллекциями.
И IEnumerable, и IQueryable используются для хранения коллекции данных и выполнения операции манипулирования данными, например, фильтрации коллекции данных. Здесь вы можете найти лучшее сравнение различий с примером. http://www.gurujipoint.com/2017/05/difference-between-ienumerable-and.html
IQueryable работает быстрее, чем IEnumerable, если мы имеем дело с огромными объемами данных из базы данных, поскольку IQueryable получает только необходимые данные из базы данных, а IEnumerable получает все данные независимо от необходимости из базы данных.
ienumerable: когда мы хотим иметь дело с оперативной памятью, то есть без подключения к данным; iqueryable: когда иметь дело с сервером sql, то есть с подключением к данным. ilist: операции, такие как добавление объекта, удаление объекта и т. д.