У чому різниця між 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 у SQL виразі LINQ постачальникам сутностей без викиду, що викидається).
Вираз може бути просто постійним вираженням самого об'єкта або більш складним деревом складеного набору операторів запитів і операндів. Викликається постачальник запитів IQueryProvider.Execute()
або IQueryProvider.CreateQuery()
методи із виразом, переданим до нього, і потім IQueryable
повертається або результат запиту, або інший відповідно.
AsQueryable()
просто додасть нумеру до числа, що підлягає запиту, і поверне його, якщо він реалізує IQueryable
інтерфейс, інакше він загорнуть його в a ConstantExpression
, на який йдеться у поверненому EnumerableQuery
об'єкті.
Основна відмінність полягає в тому, що оператори LINQ для IQueryable<T>
отримання 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
є 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 найкраще підходить для роботи з колекцією пам'яті (або локальними запитами). IEumerable не переміщується між елементами, це лише колекція вперед.
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 ", але при IE незліченно багато більше ролей буде відведено з бази даних, тоді перевірка x.name =" a "буде здійснена .NET.
Нижче згаданий невеликий тест може допомогти вам зрозуміти один із аспектів різниці між 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, і ось короткий опис виконання:
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);
}
}
Короткий зміст виконання у цьому випадку:
SELECT [Extent1].[Salary] AS [Salary]
FROM [dbo].[Employee] AS [Extent1]
Тепер річ IEnumerable
принесла всі 5 записів, присутніх у Salary
таблиці, а потім виконала фільтрацію в пам'яті на клієнтському комп'ютері, щоб отримати топ-2 записів. Тож більше даних (3 додаткових запису в даному випадку) передаються по лінії без потреби.
Ось що я написав у подібному дописі (на цю тему). (І ні, я зазвичай не цитую себе, але це дуже хороші статті.)
"Ця стаття корисна: 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 #, дерев виразів та висловлювань лямбда порівняно з виразами лямбда. . "
Ми використовуємо IEnumerable
та IQueryable
маніпулюємо даними, отриманими з бази даних. IQueryable
успадковує від IEnumerable
, тому IQueryable
містить усі IEnumerable
функції. Основна різниця між IQueryable
і IEnumerable
полягає в тому, що він IQueryable
виконує запит фільтрами, тоді як IEnumerable
спочатку виконується запит, а потім фільтрує дані на основі умов.
Нижче див. Детальну диференціацію:
IE чимало
IEnumerable
існує в System.Collections
просторі іменIEnumerable
виконати запит вибору на стороні сервера, завантажити дані в пам'ять на стороні клієнта, а потім фільтрувати даніIEnumerable
підходить для запиту даних із колекцій пам'яті, таких як List, ArrayIEnumerable
є вигідним для LINQ для Object та LINQ для XML запитівIQueyable
IQueryable
існує в System.Linq
просторі іменIQueryable
виконує "вибір запиту" на стороні сервера з усіма фільтрамиIQueryable
підходить для запитів даних із колекцій поза пам'яті (наприклад, віддалених баз даних, служб)IQueryable
корисний для LINQ для SQL запитівТак IEnumerable
зазвичай використовується для роботи з колекцією пам'яті, тоді як, IQueryable
як правило, використовується для маніпулювання колекціями.
І IEnumerable, і IQueryable використовуються для того, щоб проводити збір даних і виконувати операцію маніпулювання даними, наприклад, фільтрацію на збір даних. Тут ви можете знайти найкраще порівняння порівняння з прикладом. http://www.gurujipoint.com/2017/05/difference-between-ienumerable-and.html
IQueryable швидше IEnumerable, якщо ми маємо справу з величезною кількістю даних із бази даних, тому що IQueryable отримує лише необхідні дані з бази даних, оскільки як IEnumerable отримує всі дані незалежно від необхідності в базі даних
безліч: коли ми хочемо мати справу з обробкою пам'яті, тобто без підключення даних iqueryable: коли мати справу з сервером sql, тобто із списком підключення даних: такі операції, як додавання об'єкта, видалення об'єкта тощо