Яка різниця між IQueryable і IEnumerable


150

Я розгублений щодо різниці. Будучи досить новими для .Net, я знаю, що можу здійснювати запит, IEnumerablesвикористовуючи розширення Linq. То що це таке IQueryableі чим він відрізняється?


Дивіться також Яка різниця між IQueryable [T] та IEnumerable [T]? що перегукується з цим питанням.

Відповіді:


186

IEnumerable<T>представляє курсор, призначений тільки для переходу вперед T. .NET 3.5 додав методи розширення, що включають LINQ standard query operatorsподібні Whereі Firstз будь-якими операторами, які вимагають приймати предикати або анонімні функції Func<T>.

IQueryable<T>реалізує ті ж стандартні оператори запитів LINQ, але приймає Expression<Func<T>>для предикатів та анонімних функцій. Expression<T>являє собою складене дерево виразів, розбита версія методу («якщо наполовину складений», якщо ви хочете), яку можна проаналізувати провайдером, що перевіряється, і використовувати відповідно.

Наприклад:

IEnumerable<Person> people = GetEnumerablePeople();
Person person = people.Where(x => x.Age > 18).FirstOrDefault();

IQueryable<Person> people = GetQueryablePeople();
Person person = people.Where(x => x.Age > 18).FirstOrDefault();

У першому блоці x => x.Age > 18є анонімний метод ( Func<Person, bool>), який може бути виконаний, як і будь-який інший метод. Enumerable.Whereвиконає метод один раз для кожної людини, yielding значення, для яких метод повернувся true.

У другому блоці x => x.Age > 18- дерево виразів ( Expression<Func<Person, bool>>), яке можна розглядати як "є властивістю" Age "> 18".

Це дозволяє існувати такі речі, як LINQ-SQL, оскільки вони можуть аналізувати дерево виразів і перетворювати його в еквівалентний SQL. І оскільки постачальнику не потрібно виконувати, поки не IQueryableбуде перераховано (він реалізує IEnumerable<T>, зрештою), він може об'єднати декілька операторів запитів (у наведеному вище прикладі Whereта FirstOrDefault), щоб зробити більш розумний вибір щодо виконання всього запиту щодо базових даних джерело (наприклад, використання SELECT TOP 1в SQL).

Побачити:


1
досить коротка відповідь
ашвели

83

У реальному житті, якщо ви використовуєте ORM як LINQ-to-SQL

  • Якщо ви створюєте IQueryable, запит може бути перетворений в sql і запускатися на сервері баз даних
  • Якщо ви створили IEnumerable, то всі рядки будуть виведені в пам'ять як об’єкти перед запуском запиту.

В обох випадках, якщо ви не зателефонували ToList()або ToArray()тоді запит буде виконуватися щоразу, коли він використовується, тому, скажімо, у вас є IQueryableі ви заповнюєте 4 поля списку з нього, тоді запит буде запущено проти бази даних 4 рази.

Також якщо ви розширите свій запит:

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

Тоді із IQueryableзгенерованим SQL міститиметься where name = "a", але з IEnumerableнабагато більшою роллю буде виведено назад із бази даних, тоді x.name = "a"перевірку зробить .NET.


"запит може бути перетворений в sql": я не отримав "може бути". Крім того, якщо я маю IEnumerable і створюю "складний ланцюг", то (очевидно) на відміну від IQueryable, він не буде переведений на "оптимізований" SQL-запит. Просто хочу підтвердити, що це означає, коли ви говорите «усі рядки будуть втягнуті в пам’ять». Скажімо, що у мене є два пункти, то чи всі кортежі сутності спочатку потраплять у пам'ять, а потім відбудеться нормальна фільтрація "в пам'яті"?
Вайбхав

36

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

Джерело: тут


19

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

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

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


11

Принципова відмінність полягає в тому, що IEnumerable буде перераховувати всі його елементи весь час, тоді як IQueryable буде перераховувати елементи або навіть робити інші речі на основі запиту. Запит - це вираз (представлення даних .Net-коду), який IQueryProvider повинен досліджувати / інтерпретувати / компілювати / будь-що для того, щоб генерувати результати.

Наявність виразу запиту дає дві переваги.

Перша перевага - оптимізація. Оскільки модифікатори типу "Where" включені до виразу запиту, IQueryProvider може застосовувати інакше неможливі оптимізації. Замість того, щоб повернути всі елементи, а потім викинути більшість із них через пункт "Де", провайдер може використовувати хеш-таблицю, щоб знайти елементи за допомогою заданого ключа.

Друга перевага - гнучкість. Оскільки вирази - це досліджувані структури даних, ви можете робити такі речі, як серіалізація запиту та надсилати їх на віддалену машину (наприклад, linq-to-sql).



1

По-перше, IEnumerable знаходяться в просторі імен System.Collections, а IQueryable - у просторі імен System.Linq. Якщо ви використовуєте IEnumerable під час запитів даних із колекцій пам'яті, таких як List, Array collection тощо. І коли запитуйте дані з колекцій поза пам'яті (наприклад, віддаленої бази даних, сервісу), ви використовуєте IQueryable. Оскільки під час запиту даних із бази даних, IEnumerable виконує вибір запиту на стороні сервера, завантажує дані в пам'ять на стороні клієнта, а потім фільтрує дані. Отже, більше працює і стає повільним. Під час запитів даних з бази даних IQueryable виконує вибір запиту на стороні сервера з усіма фільтрами. Отже, працює менше і стає швидким.

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