我注意到上面@gunny229 的回答中有几个问题,这就是我写这篇文章的原因。我在他的帖子的评论区也提到了这些问题。为了更正那个帖子,我几乎不得不重写整个帖子,所以我想创建自己的帖子。我不打算完全解决 OP 的问题,但我想指出 使用 LINQ to SQL 时 IQueryable 和 IEnumerable 之间的区别。
我在 DB(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 表中获取前 2 条记录。因此,我在控制台应用程序中添加了一个 ADO.NET 实体数据模型项,指向数据库中的 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 Server 实例上启动了一个 SQL 查询分析器会话,这里是执行摘要:
- 触发的查询总数:1
- 查询文本:
SELECT TOP (2) [c].[Salary] AS [Salary] FROM [dbo].[Employee] AS [c]
只是IQueryable 足够聪明,可以在数据库服务器端应用Top (2) 子句,因此它只通过网络传输5 条记录中的2 条。在客户端计算机端根本不需要任何进一步的内存过滤。
IEnumerable 路由代码:
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 带来了Salary 表中存在的所有 5 条记录,然后在客户端计算机上执行内存过滤以获得前 2 条记录。因此,更多数据(在本例中为 3 条额外记录)不必要地通过网络传输。