Ответ
Интерфейс IQueryable<T> наследует от IEnumerable<T> и IQueryable. Его ключевая особенность — отложенное выполнение (deferred execution) и построение запроса в виде дерева выражений (Expression), которое может быть транслировано в другой язык (например, SQL).
Основные свойства, определенные в IQueryable и IQueryable<T>:
Expression— возвращает дерево выражений (System.Linq.Expressions.Expression), которое представляет запрос. Это «описание» запроса, а не его результат.ElementType— возвращает тип элементов в результирующей последовательности (например,User).Provider— возвращает объект-поставщик запросов (IQueryProvider), который отвечает за компиляцию дерева выражений и его выполнение на целевом источнике данных (например, в базе данных через Entity Framework).
Почему это важно? В отличие от IEnumerable, методы IQueryable (такие как Where, OrderBy, Select) не выполняют операцию сразу. Вместо этого они модифицируют дерево выражений. Запрос выполняется только при материализации — вызове метода, который приводит к перечислению результатов (например, ToList(), ToArray(), FirstOrDefault(), Count()).
Пример:
// DbContext использует IQueryable
IQueryable<User> query = dbContext.Users
.Where(u => u.Age > 18) // Добавляет условие в Expression
.OrderBy(u => u.LastName) // Добавляет сортировку в Expression
.Select(u => new { u.Id, u.Name }); // Добавляет проекцию в Expression
// Запрос НЕ выполнен. Он представлен в виде Expression и Provider.
Console.WriteLine(query.Expression); // Можно посмотреть сгенерированное выражение
// МАТЕРИАЛИЗАЦИЯ: запрос транслируется в SQL и выполняется на сервере БД.
var adultUsers = query.ToList();
Ключевое отличие от IEnumerable: |
Аспект | IEnumerable<T> |
IQueryable<T> |
|---|---|---|---|
| Место выполнения | В памяти приложения (LINQ to Objects). | На стороне провайдера данных (например, SQL-сервер). | |
| Фильтрация | Where(u => u.Age > 18) загружает ВСЕ данные, затем фильтрует в памяти. |
Where(u => u.Age > 18) добавляет условие WHERE Age > 18 в SQL-запрос. |
|
| Оптимизация | Меньше возможностей для оптимизации. | Провайдер может оптимизировать итоговый запрос (индексы, JOIN). |
Использование IQueryable критически важно для эффективной работы с базами данных, так как позволяет выполнять фильтрацию, сортировку и пагинацию на стороне СУБД, а не загружать все строки в память.