Рейтинговые книги
Читем онлайн Язык программирования C#9 и платформа .NET5 - Троелсен Эндрю

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 460 461 462 463 464 465 466 467 468 ... 642

Энергичная загрузка связанных данных

В предыдущей главе объяснялось, что сущности, которые связаны через навигационные свойства, могут создаваться в одном запросе с применением энергичной загрузки. Метод Include() указывает соединение со связанной сущностью, а метод ThenInclude() используется для последующих соединений. Оба метода будут задействованы в рассматриваемых далее тестах. Как упоминалось ранее, когда методы Include()/ThenInclude() транслируются в SQL, для обязательных отношений применяется внутреннее соединение, а для необязательных — левое соединение.

Поместите в файл класса CarTests.cs следующий тест, чтобы продемонстрировать одиночный вызов Include():

[Fact]

public void ShouldGetAllOfTheCarsWithMakes()

{

 IIncludableQueryable<Car, Make?> query =

  Context.Cars.<b>Include(c =&gt; c.MakeNavigation)</b>;

  var queryString = query.ToQueryString();

  var cars = query.ToList();

  Assert.Equal(9, cars.Count);

}

Тест добавляет к результатам свойство MakeNavigation, выполняя внутреннее соединение с помощью показанного ниже кода SQL. Обратите внимание, что глобальный фильтр запросов действует:

SELECT [i].[Id], [i].[Color], [i].[IsDrivable], [i].[MakeId], [i].[PetName],

       [i].[TimeStamp], [m].[Id], [m].[Name], [m].[TimeStamp]

FROM [dbo].[Inventory] AS [i]

INNER JOIN [dbo].[Makes] AS [m] ON [i].[MakeId] = [m].[Id]

WHERE [i].[IsDrivable] = CAST(1 AS bit)

Во втором тесте используется два набора связанных данных. Первый — это получение информации Make (как и в предыдущем тесте), а второй — получение сущностей Order и затем присоединенных к ним сущностей Customer. Полный тест также отфильтровывает записи Car, для которых есть записи Order. Для необязательных отношений генерируются левые соединения:

[Fact]

public void ShouldGetCarsOnOrderWithRelatedProperties()

{

  IIncludableQueryable&lt;Car, Customer?&gt; query = Context.Cars

<b>    .Where(c =&gt; c.Orders.Any())</b>

<b>    .Include(c =&gt; c.MakeNavigation)</b>

<b>    .Include(c =&gt; c.Orders).ThenInclude(o =&gt; o.CustomerNavigation);</b>

  var queryString = query.ToQueryString();

  var cars = query.ToList();

  Assert.Equal(4, cars.Count);

(window.adrunTag = window.adrunTag || []).push({v: 1, el: 'adrun-4-390', c: 4, b: 390})

  cars.ForEach(c =&gt;

  {

    Assert.NotNull(c.MakeNavigation);

    Assert.NotNull(c.Orders.ToList()[0].CustomerNavigation);

  });

}

Вот сгенерированный запрос:

SELECT [i].[Id], [i].[Color], [i].[IsDrivable], [i].[MakeId], [i].[PetName],

       [i].[TimeStamp], [m].[Id], [m].[Name], [m].[TimeStamp], [t0].[Id],

       [t0].[CarId], [t0].[CustomerId], [t0].[TimeStamp], [t0].[Id0],

       [t0].[TimeStamp0], [t0].[FirstName], [t0].[FullName],

    [t0].[LastName], [t0].[Id1]

FROM [dbo].[Inventory] AS [i]

     INNER JOIN [dbo].[Makes] AS [m] ON [i].[MakeId]=[m].[Id]

     LEFT JOIN(SELECT [o].[Id], [o].[CarId], [o].[CustomerId], [o].[TimeStamp],

        [c].[Id] AS [Id0], [c].[TimeStamp] AS [TimeStamp0],

        [c].[FirstName], [c].[FullName], [c].[LastName], [t].[Id] AS [Id1]

       FROM [dbo].[Orders] AS [o]

         INNER JOIN(SELECT [i0].[Id], [i0].[IsDrivable]

           FROM [dbo].[Inventory] AS [i0]

           WHERE [i0].[IsDrivable]=CAST(1 AS BIT)) AS [t] ON

                 [o].[CarId]=[t].[Id]

         INNER JOIN [dbo].[Customers] AS [c] ON [o].[CustomerId]=[c].[Id]

       WHERE [t].[IsDrivable]=CAST(1 AS BIT)) AS [t0] ON [i].[Id]=[t0].[CarId]

   WHERE([i].[IsDrivable]=CAST(1 AS BIT))AND EXISTS (SELECT 1

     FROM [dbo].[Orders] AS [o0]

       INNER JOIN(SELECT [i1].[Id], [i1].[Color], [i1].[IsDrivable],

                         [i1].[MakeId], [i1].[PetName], [i1].[TimeStamp]

     FROM [dbo].[Inventory] AS [i1]

     WHERE [i1].[IsDrivable]=CAST(1 AS BIT)) AS [t1] ON [o0].[CarId]=[t1].[Id]

     WHERE([t1].[IsDrivable]=CAST(1 AS BIT)) AND([i].[Id]=[o0].[CarId]))

ORDER BY [i].[Id], [m].[Id], [t0].[Id], [t0].[Id1], [t0].[Id0];

Разделение запросов к связанным данным

Чем больше соединений добавляется в запрос LINQ, тем сложнее становится результирующий запрос. В версии EF Core 5 появилась возможность выполнять сложные соединения как разделенные запросы. Детальное обсуждение ищите в предыдущей главе, но вкратце помещение в запрос LINQ вызова метода AsSplitQuery() инструктирует инфраструктуру EF Core о необходимости разделения одного обращения к базе данных на несколько обращений. В итоге может повыситься эффективность, но возникает риск несогласованности данных. Добавьте в тестовую оснастку приведенный далее тест:

1 ... 460 461 462 463 464 465 466 467 468 ... 642
На этой странице вы можете бесплатно читать книгу Язык программирования C#9 и платформа .NET5 - Троелсен Эндрю бесплатно.
Похожие на Язык программирования C#9 и платформа .NET5 - Троелсен Эндрю книги

Оставить комментарий