繁体   English   中英

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

[英]IQueryable vs IEnumerable - how many DB calls?

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

以下是我的问题

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

如果我是对的,有 2 个 DB 调用,一个使用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
    }

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

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

我的理解是 DB 调用是使用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 查询总是在迭代查询变量时执行,而不是在创建查询变量时执行。

因此,当您访问 firstEmployee 变量时,只会进行一次调用。

第二部分说明

IQueryable也是 IEnumerable。 所以这一行:

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

不强制转换为 IEnumerable。 当您访问firstEmployee变量时, empDetails仍然是IQueryable并将再次执行。

仅在需要时才通过执行查询进行优化。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM