День сто двадцать восьмой. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по C#
14. В чём разница между IEnumerable и IQueryable?
При работе с базой данных иногда можно запутаться. Могут возникнуть некоторые вопросы, например, что использовать для извлечения данных из БД,
Если коротко:
-
-
Разница в том, что
В случае
По сути, есть два идентичных набора расширений LINQ.
Сигнатура для
При использовании
Зачем заморачиваться с этими деревьями выражений? Я просто хочу, чтобы Where фильтровал мои данные. Основная причина в том, что Entity Framework и Linq2SQL могут преобразовывать деревья выражений непосредственно в SQL, поэтому ваш код будет выполняться намного быстрее.
Это похоже на бесплатное повышение производительности. То есть надо везде использовать AsQueryable? Нет,
Источники:
- https://www.c-sharpcorner.com
- https://stackoverflow.com/questions/2876616/returning-ienumerablet-vs-iqueryablet
Самые часто задаваемые вопросы на собеседовании по C#
14. В чём разница между IEnumerable и IQueryable?
При работе с базой данных иногда можно запутаться. Могут возникнуть некоторые вопросы, например, что использовать для извлечения данных из БД,
IEnumerable
или IQueryable
?Если коротко:
-
IEnumerable
- выполняет запрос SELECT
на стороне сервера, загружает все данные в память на стороне клиента, а затем выполняет фильтрацию.-
IQueryable
- выполняет запрос SELECT
на стороне сервера со всеми фильтрами.Разница в том, что
IQueryable<T>
- это интерфейс, который позволяет работать LINQ-to-SQL (на самом деле, LINQ-to-чтоугодно). Поэтому, если вы дополнительно уточните свой запрос в IQueryable<T>
, этот запрос будет выполнен в базе данных, если это возможно.В случае
IEnumerable<T>
это будет LINQ-to-object, то есть все объекты, соответствующие исходному запросу, должны быть загружены в память из базы данных:IQueryable<Customer> custs = ...;Этот код выполнит SQL-запрос для выбора только золотых клиентов. А вот следующий код выполнит исходный запрос к базе данных, а затем отфильтрует не-золотых клиентов в памяти:
// Затем...
var goldCustomers = custs.Where(c => c.IsGold);
IEnumerable<Customer> custs = ...;Это довольно важное различие, и работа с
// Затем...
var goldCustomers = custs.Where(c => c.IsGold);
IQueryable
может во многих случаях избавить вас от возвращения слишком большого количества строк из базы данных. Другим ярким примером является разбиение на страницы: если вы используете Take
и Skip
с IQueryable
, вы получите только запрошенные строки, а выполнение этого в IEnumerable
приведет к загрузке в память всех строк.По сути, есть два идентичных набора расширений LINQ.
Where
, Sum
, Count
, FirstOrDefault
и т.д. имеют две версии: одна, которая принимает функции, и другая, которая принимает выражения.Сигнатура для
IEnumerable
: Where(Func<Customer, bool> predicate)
Сигнатура для IQueryable
: Where(Expression<Func<Customer, bool>> predicate)
Вы, вероятно, использовали обе версии, не осознавая этого, потому что обе вызываются с использованием идентичного синтаксиса Where(x => x.City == "<City>")
, который работает как для IEnumerable
, так и для IQueryable
.При использовании
Where
с IEnumerable
компилятор передает в Where
скомпилированную функцию. А при использовании Where
с IQueryable
компилятор передает в Where
дерево выражений. Дерево выражений похоже на отражение, но для кода. Компилятор преобразует ваш код в структуру данных, которая описывает, что ваш код делает в формате, который легко усваивается.Зачем заморачиваться с этими деревьями выражений? Я просто хочу, чтобы Where фильтровал мои данные. Основная причина в том, что Entity Framework и Linq2SQL могут преобразовывать деревья выражений непосредственно в SQL, поэтому ваш код будет выполняться намного быстрее.
Это похоже на бесплатное повышение производительности. То есть надо везде использовать AsQueryable? Нет,
IQueryable
полезен, только если базовый поставщик данных может что-то с ним сделать. Преобразование обычного List
в IQueryable
не даст вам никакой выгоды.Источники:
- https://www.c-sharpcorner.com
- https://stackoverflow.com/questions/2876616/returning-ienumerablet-vs-iqueryablet