IQueryable против IEnumerable - сколько вызовов в БД? - PullRequest
1 голос
/ 06 января 2020

Я знаю, как работают IQueryable и IEnumerable. Но сегодня, когда я пересматривал эти темы на примере.

Ниже приведены мои вопросы

Сколько вызовов в БД сделано?

Если я прав, то есть два вызова БД, один с 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());
}

Может кто-нибудь поправить меня, если мое понимание неверно.

Заранее спасибо

1 Ответ

2 голосов
/ 06 января 2020

Проверьте Документацию по выполнению запроса

После того как запрос LINQ создан пользователем , он преобразуется в дерево команд. Дерево команд - это представление запроса, совместимого с Entity Framework. Затем дерево команд выполняется для источника данных. Во время выполнения запроса оцениваются все выражения запроса (то есть все компоненты запроса), включая те выражения, которые используются при материализации результата.

После того, как запрос 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. empDetails остается IQueryable и будет выполняться снова при доступе к переменной firstEmployee.

Is оптимизируется путем выполнения запроса, только когда он необходим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...