Чтение онлайн

ЖАНРЫ

Язык программирования C#9 и платформа .NET5
Шрифт:

Методы

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), но в веб-приложениях и службах использовать ее не рекомендуется, так что в книге она не рассматривается. За дополнительными сведениями о ленивой загрузке и ее применением с EF Core обращайтесь в документацию по ссылке

https://docs.microsoft.com/ru-ru/ef/core/querying/related-data/lazy
.

Глобальные фильтры запросов

Поделиться с друзьями: