.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().