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

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

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 274 275 276 277 278 279 280 281 282 ... 407
Перейти на страницу:
(один оператор LINQ, множество запросов SQL), явным образом (множество вызовов LINQ, множество запросов SQL) или ленивым образом (один оператор LINQ, множество запросов SQL по требованию).

Помимо возможности загрузки связанных данных с применением навигационных свойств исполняющая среда EF Core будет автоматически приводить в порядок сущности по мере их загрузки в ChangeTracker. В качестве примера предположим, что все записи Make загружаются в DbSet<Make>, после чего все записи Car загружаются в DbSet<Car>. Несмотря на то что записи загружались по отдельности, они будут доступны друг другу через навигационные свойства.

Энергичная загрузка

Энергичная загрузка — это термин для обозначения загрузки связанных записей из множества таблиц в рамках одного обращения к базе данных. Прием аналогичен созданию запроса в Т-SQL, связывающего две или большее число таблиц с помощью соединений. Когда сущности имеют навигационные свойства, которые используются в запросах LINQ, механизм трансляции применяет соединения, чтобы получить данные из связанных таблиц, и загружает соответствующие сущности. Такое решение обычно гораздо эффективнее, чем выполнение одного запроса с целью получения данных из одной таблицы и выполнение дополнительных запросов для каждой связанной таблицы. В ситуациях, когда использовать один запрос менее эффективно, в EF Core 5 предусмотрено разделение запросов, которое рассматривается далее.

Методы Include() и ThenInclude() (для последующих навигационных свойств) применяются для обхода навигационных свойств в запросах LINQ. Если отношение является обязательным, тогда механизм трансляции LINQ создаст внутреннее соединение. Если же отношение необязательное, то механизм трансляции создаст левое соединение.

Например, чтобы загрузить все записи Car со связанной информацией Make, запустите следующий запрос LINQ:

var queryable = Context.Cars.IgnoreQueryFilters().Include(

  c => c.MakeNavigation).ToList();

Предыдущий запрос LINQ выполняет в отношении базы данных такой запрос:

SELECT [i].[Id], [i].[Color], [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]

В одном запросе можно использовать множество вызовов Include() для соединения исходной сущности сразу с несколькими сущностями. Чтобы спуститься вниз по дереву навигационных свойств, применяйте ThenInclude() после Include(). Скажем, для получения всех записей Cars со связанной информацией Make и Order, а также информацией Customer, связанной с Order, используйте показанный ниже оператор:

var cars = Context.Cars.Where(c => c.Orders.Any())

  .Include(c => c.MakeNavigation)

  .Include(c => c.Orders).ThenInclude(o => o.CustomerNavigation).ToList();

Фильтрованные включаемые данные

В версии EF Core 5 появилась возможность фильтрации и сортировки включаемых данных. Допустимыми операциями при навигации по коллекции являются Where(), OrderBy(), OrderByDescending(), ThenBy(), ThenByDescending(), Skip() и Take(). Например, если нужно получить все записи Make, но только со связанными записями Car с желтым цветом, тогда вы организуете фильтрацию навигационного свойства в лямбда-выражении такого вида:

var query = Context.Makes

    .Include(x => x.Cars.Where(x=>x.Color == "Yellow")).ToList();

В результате запустится следующий запрос:

SELECT [m].[Id], [m].[Name], [m].[TimeStamp], [t].[Id], [t].[Color],

  [t].[MakeId], [t].[PetName], [t].[TimeStamp]

FROM [dbo].[Makes] AS [m]

LEFT JOIN (

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

    FROM [Dbo].[Inventory] AS [i]

    WHERE [i].[Color] = N'Yellow') AS [t] ON [m].[Id] = [t].[MakeId]

ORDER BY [m].[Id], [t].[Id]

Энергичная загрузка с разделением запросов

Наличие в запросе LINQ множества вызовов Include() может отрицательно повлиять на производительность. Для решения проблемы в EF Core 5 были введены разделяемые запросы. Вместо выполнения одиночного запроса исполняющая среда EF Core будет разделять запрос LINQ на несколько запросов SQL и затем объединять все связанные данные. Скажем, добавив к запросу LINQ вызов AsSplitQuery(), можно ожидать, что предыдущий запрос будет представлен в виде множества запросов SQL:

var query = Context.Makes.AsSplitQuery()

  .Include(x => x.Cars.Where(x=>x.Color == "Yellow")).ToList();

Вот как выглядят выполняемые запросы:

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

FROM [dbo].[Makes] AS [m]

ORDER BY [m].[Id]

SELECT [t].[Id], [t].[Color], [t].[MakeId], [t].[PetName],

       [t].[TimeStamp], [m].[Id]

FROM [dbo].[Makes] AS [m]

INNER JOIN (

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

    FROM [Dbo].[Inventory] AS [i]

    WHERE [i].[Color] = N'Yellow'

) AS [t] ON [m].[Id] = [t].[MakeId]

ORDER BY [m].[Id]

Применению разделяемых запросов присущ и недостаток: если данные изменяются между выполнением запросов, тогда возвращаемые данные будут несогласованными.

Явная загрузка

Явная загрузка — это загрузка данных по навигационному свойству после того, как главный объект уже загружен. Такой процесс включает в себя дополнительное обращение к базе данных для получения связанных данных. Прием может быть удобен, если приложению необходимо получать связанные записи выборочно на основе какого-то действия пользователя, а не извлекать все связанные записи.

Процесс начинается с уже загруженной сущности и использования метода Entry() на экземпляре производного от DbContext класса. При запросе в отношении навигационного свойства типа ссылки (например, с целью получения информации Make для автомобиля) применяйте метод Reference(). При запросе в отношении навигационного свойства типа коллекции используйте метод Collection(). Выполнение запроса откладывается до вызова Load(), ToList() или агрегирующей функции (вроде Count() либо Мах()).

В следующих примерах показано, как получить связанные данные о производителе и заказах для записи Car:

// Получить запись Car.

var car = Context.Cars.First(x => x.Id == 1);

// Получить информацию о производителе.

Context.Entry(car).Reference(c => c.MakeNavigation).Load();

// Получить заказы, к которым относится данная запись Car.

Context.Entry(car).Collection(c => c.Orders).Query().

  IgnoreQueryFilters().Load();

Ленивая загрузка

Ленивая загрузка представляет собой загрузку записи по требованию, когда навигационное свойство применяется для доступа к связанной записи, которая пока еще не загружена в память. Ленивая загрузка — это средство EF 6, снова добавленное в версию EF Core 2.1. Хотя включение ленивой загрузки кажется разумной идеей, временами она может стать причиной возникновения проблем с производительностью в вашем приложении из-за потенциально лишних циклов взаимодействия с базой данных. В результате по умолчанию ленивая загрузка в EF Core отключена (в EF 6 она была включена).

Ленивая загрузка может быть полезна в приложениях интеллектуальных клиентов (WPF, Windows Forms), но в веб-приложениях и службах использовать ее не рекомендуется, так что в книге

1 ... 274 275 276 277 278 279 280 281 282 ... 407
Перейти на страницу:

Комментарии
Минимальная длина комментария - 20 знаков. В коментария нецензурная лексика и оскорбления ЗАПРЕЩЕНЫ! Уважайте себя и других!
Комментариев еще нет. Хотите быть первым?