В чем разница между IQueryable <T>и IEnumerable <T>? - PullRequest
402 голосов
/ 31 октября 2008

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


См. Также В чем разница между IQueryable и IEnumerable , который перекрывает этот вопрос.

Ответы [ 13 ]

246 голосов
/ 31 октября 2008

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

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

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

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

190 голосов
/ 31 октября 2008

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

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

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

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

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

Подробнее:

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

172 голосов
/ 29 апреля 2014

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

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

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

enter image description here

Есть много отличий, но давайте поговорим об одной большой разнице, которая имеет самое большое значение. 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, равным 2.

enter image description here

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

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

enter image description here

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

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

54 голосов
/ 10 мая 2012

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

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

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

18 голосов
/ 16 мая 2013

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

17 голосов
/ 04 сентября 2014

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

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

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

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

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

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

10 голосов
/ 15 ноября 2012

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

8 голосов
/ 26 апреля 2017

Приведенный ниже небольшой тест может помочь вам понять один аспект различия между 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 Query на своем экземпляре SQL Server, и вот сводная таблица выполнения:

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

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

Код для IEnumerable route :

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 голосов
/ 14 марта 2014

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

"Эта статья полезна: 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 #, деревьев выражений и лямбда-операторов по сравнению с лямбда-выражениями.".

2 голосов
/ 11 апреля 2019

Мы используем IEnumerable и IQueryable для манипулирования данными, полученными из базы данных. IEnumerable наследуется от IQueryable, поэтому 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 обычно используется для манипулирования коллекциями.

...