Яка різниця між 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 у SQL виразі LINQ постачальникам сутностей без викиду, що викидається).

Вираз може бути просто постійним вираженням самого об'єкта або більш складним деревом складеного набору операторів запитів і операндів. Викликається постачальник запитів IQueryProvider.Execute()або IQueryProvider.CreateQuery()методи із виразом, переданим до нього, і потім IQueryableповертається або результат запиту, або інший відповідно.


8
Чи є якась користь від використання AsQueryable?
Йорданія

6
Єдина перевага - зручність. AsQueryable()просто додасть нумеру до числа, що підлягає запиту, і поверне його, якщо він реалізує IQueryableінтерфейс, інакше він загорнуть його в a ConstantExpression, на який йдеться у поверненому EnumerableQueryоб'єкті.
Марк Сідаде


1
Варто прочитати цю статтю
JenonD

Посилання @JenonD мертве, ось шляхbackmachine: web.archive.org/web/20160904162931/http://www.dotnet-tricks.com/…
травень

201

Основна відмінність полягає в тому, що оператори LINQ для IQueryable<T>отримання Expressionоб'єктів замість делегатів, що означає логіку користувальницького запиту, яку він отримує, наприклад, селектор предикатів чи значень, у формі дерева виразів замість делегата методу.

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

Виконання запиту:

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

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

Більше в:

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


14
Мені подобається згадка про операції поза пам'яттю. Це пояснює реальну практичну різницю у використанні.
Ізмаїл Смирнов

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

дещо готове
jbooker

@joey Тим не менш, я бачу це зображення чудово у цій відповіді: i.stack.imgur.com/2DAqv.jpg
VonC

190

Це приємне відео на YouTube, яке демонструє, як відрізняються ці інтерфейси, які варто переглянути.

Нижче наведена довга описова відповідь.

Перший важливий момент, який слід пам'ятати, - це IQueryableуспадкований інтерфейс IEnumerable, тому все, що IEnumerableможна зробити, IQueryableтакож може зробити.

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

Існує багато відмінностей, але давайте обговоримо про одну велику різницю, яка робить найбільшу різницю. IEnumerableІнтерфейс корисний, коли ваша колекція завантажується за допомогою LINQEntity 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.

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

Але тепер побачити нижче код , який ми змінили 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 () об'єкта сутності, а потім Виберіть () у переглядний модель, що містить DateTime. Цей процес використовує функції пам'яті.
Джефф Лі

57

IEnumerable: IEnumerable найкраще підходить для роботи з колекцією пам'яті (або локальними запитами). IEumerable не переміщується між елементами, це лише колекція вперед.

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

Отже, коли вам доведеться просто повторити колекцію пам'яті, використовуйте IEnumerable, якщо вам потрібно здійснити будь-які маніпуляції зі збіркою, як набір даних та іншими джерелами даних, використовуйте IQueryable


3
Чи IE численні не використовують відкладене виконання?
Ян Варбуртон

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 ", але при IE незліченно багато більше ролей буде відведено з бази даних, тоді перевірка x.name =" a "буде здійснена .NET.


10

IEnumerable посилається на колекцію, але IQueryable - це лише запит, і він буде генерований всередині дерева виразів. Ми будемо запускати цей запит, щоб отримати дані з бази даних.


8

Нижче згаданий невеликий тест може допомогти вам зрозуміти один із аспектів різниці між 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

Тепер моєю метою було просто отримати топ-2 записи з Employeeтаблиці в базі даних. Я додав елемент моєї моделі даних ADO.NET в свою консольну програму, вказуючи на Employeeтаблицю в базі даних, і почав писати запити LINQ.

Код маршруту IQueyable :

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 записів по дроту. Будь-яка подальша фільтрація в пам'яті взагалі не потрібна на клієнтському комп'ютері.

Код IE численного маршруту :

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таблиці, а потім виконала фільтрацію в пам'яті на клієнтському комп'ютері, щоб отримати топ-2 записів. Тож більше даних (3 додаткових запису в даному випадку) передаються по лінії без потреби.


7

Ось що я написав у подібному дописі (на цю тему). (І ні, я зазвичай не цитую себе, але це дуже хороші статті.)

"Ця стаття корисна: IQueryable vs IEnumerable в LINQ-to-SQL .

Цитуючи цю статтю, "Відповідно до документації MSDN, виклики, зроблені на IQueryable, функціонують, створюючи натомість дерево внутрішнього вираження. "Ці методи, що розширюють IQueryable (Of T), не виконують жодного запиту безпосередньо. Натомість їх функціональність полягає у створенні об'єкта Expression, який є деревом виразів, що представляє сукупний запит." '

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

Ось ще одна дуже корисна стаття, в якій детально розглядаються відмінності з точки зору поштовху та потягу. (Під "натисканням" проти "потягу" я маю на увазі напрямок потоку даних. Методи реактивного програмування для .NET та C #

Ось дуже гарна стаття, в якій детально описані відмінності між лямбдазами висловлювань та лямбдами виразів та більш детально розглядаються поняття виразного тресу: Перегляд делегатів C #, дерев виразів та висловлювань лямбда порівняно з виразами лямбда. . "


6

Ми використовуємо IEnumerableта IQueryableманіпулюємо даними, отриманими з бази даних. IQueryableуспадковує від IEnumerable, тому IQueryableмістить усі IEnumerableфункції. Основна різниця між IQueryableі IEnumerableполягає в тому, що він IQueryableвиконує запит фільтрами, тоді як IEnumerableспочатку виконується запит, а потім фільтрує дані на основі умов.

Нижче див. Детальну диференціацію:

IE чимало

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

IQueyable

  1. IQueryableіснує в System.Linqпросторі імен
  2. IQueryable виконує "вибір запиту" на стороні сервера з усіма фільтрами
  3. IQueryable підходить для запитів даних із колекцій поза пам'яті (наприклад, віддалених баз даних, служб)
  4. IQueryable корисний для LINQ для SQL запитів

Так IEnumerableзазвичай використовується для роботи з колекцією пам'яті, тоді як, IQueryableяк правило, використовується для маніпулювання колекціями.


3

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


2

IQueryable швидше IEnumerable, якщо ми маємо справу з величезною кількістю даних із бази даних, тому що IQueryable отримує лише необхідні дані з бази даних, оскільки як IEnumerable отримує всі дані незалежно від необхідності в базі даних


0

безліч: коли ми хочемо мати справу з обробкою пам'яті, тобто без підключення даних iqueryable: коли мати справу з сервером sql, тобто із списком підключення даних: такі операції, як додавання об'єкта, видалення об'єкта тощо

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.