IQueryable vs IEnumerable - 有多少个数据库调用?



我知道IQueryableIEnumerable是如何工作的。但是今天,当我用一个例子重新审视这些主题时。

以下是我的问题

进行了多少次数据库调用?

如果我是对的,有 2 个数据库调用,一个带有where子句,另一个在使用Take(1)时调用。

public void GetEmployeesByDept(long deptId)
{
IQueryable<EmployeeDetails> empDetails = _context.EmployeeDetails.Where(x => x.Idseq == deptId);
// First DB call
var firstEmployee = empDetails.Take(1);
// Second DB call
Console.WriteLine(empDetails.GetType());
}

这是我的解释 - 但是当我将鼠标悬停在empDetails上时,我可以看到表达式包含两个参数

  1. With the table

  2. $x.Idseq == .Constant<TestProject.Program+<>c__DisplayClass2_0>(TestProject.Program+<>c__DisplayClass2_0).deptId

所以,现在当执行完成firstEmployee时,我将鼠标悬停在firstEmployee变量上,我可以看到表达式如下

这也是数据库调用吗?

.Call System.Linq.Queryable.Take(
.Call System.Linq.Queryable.Where(
.Constant<Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[Employee.Models.EmployeeDetails]>(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[Employee.Models.EmployeeDetails]),
'(.Lambda #Lambda1<System.Func`2[Employee.Models.EmployeeDetails,System.Boolean]>)),
1).Lambda #Lambda1<System.Func`2[Employee.Models.EmployeeDetails,System.Boolean]>(Employee.Models.EmployeeDetails $x)
{
$x.Idseq == .Constant<TestProject.Program+<>c__DisplayClass2_0>(TestProject.Program+<>c__DisplayClass2_0).deptId
}

如果这是两者中唯一的数据库调用,那么我为什么能够加载 empDetails 的数据?

问题#2:现在,我将类型从IQueryable更改为IEnumerable

我在这里的理解是数据库调用是使用where子句进行的,然后将数据加载到内存中,然后获取第一个元素。

这是真的吗?

public void GetEmployeesByDept(long deptId)
{
IEnumerable<EmployeeDetails> empDetails = _context.EmployeeDetails.Where(x => x.Idseq == deptId);
// First DB call
var firstEmployee = empDetails.Take(1); // in-memory object
Console.WriteLine(empDetails.GetType());
}

如果我的理解不正确,谁能纠正我。

提前致谢

查看查询执行文档

用户创建 LINQ 查询后,该查询将转换为命令树。命令树是与实体框架兼容的查询的表示形式。然后针对数据源执行命令树。在查询执行时,将计算所有查询表达式(即查询的所有组件(,包括结果具体化中使用的那些表达式。

用户创建 LINQ 查询后

您将在以下行中创建查询

IQueryable<EmployeeDetails> empDetails = _context.EmployeeDetails.Where(x => x.Idseq == deptId);
// first DB call
var firstEmployee = empDetails.Take(1);

LINQ 查询始终在循环访问查询变量时执行,而不是在创建查询变量时执行。

因此,当您访问第一个员工变量时,只会进行一次调用。

第二部分说明

IQueryable也是IEnumerable。所以这行:

IEnumerable<EmployeeDetails> empDetails = _context.EmployeeDetails.Where(x => x.Idseq ==deptId);

不强制转换为 IEnumerable。empDetails保持IQueryable,并在您访问firstEmployee变量时再次执行。

仅在需要时通过执行查询来优化 IS。

最新更新