Приведенный ниже небольшой тест может помочь вам понять один аспект различия между 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
Теперь моя цель состояла в том, чтобы просто получить две лучшие записи из таблицы Employee
в базе данных. Я добавил элемент ADO.NET Entity Data Model в консольное приложение, указывая на таблицу Employee
в моей базе данных, и начал писать запросы LINQ.
Код для маршрута IQueryable :
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
- Текст запроса:
SELECT TOP (2) [c].[Salary] AS [Salary] FROM [dbo].[Employee] AS [c]
Просто IQueryable
достаточно умен, чтобы применить условие Top (2)
на самой стороне сервера базы данных, поэтому он переносит только 2 из 5 записей по проводам. Дальнейшая фильтрация в памяти вообще не требуется на стороне клиентского компьютера.
Код для IEnumerable route :
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
- Текст запроса, захваченный в профилировщике SQL:
SELECT [Extent1].[Salary] AS [Salary]
FROM [dbo].[Employee] AS [Extent1]
Теперь дело в том, что IEnumerable
собрал все 5 записей, представленных в таблице Salary
, а затем выполнил фильтрацию в памяти на клиентском компьютере, чтобы получить первые две записи. Поэтому больше данных (в данном случае 3 дополнительных записи) были переданы по проводам без необходимости.