Какой командой можно загрузить подколлекцию в Entity Framework
Что проверяют
Знаете ли вы три стратегии загрузки связанных данных в EF и понимаете ли, во что каждая превращается на уровне SQL. Следом почти всегда спрашивают про проблему N+1 и про то, что будет, если подключить через Include две коллекции сразу.
Как отвечать
Базовый ответ: Include, для вложенных уровней ThenInclude. context.Blogs.Include(b => b.Posts).ThenInclude(p => p.Comments) загрузит блоги, их посты и комментарии к постам. Это жадная загрузка (eager loading).
Дальше покажите, что знаете остальные варианты:
- явная загрузка: сущность уже в памяти, коллекцию дочитывают отдельно через
await context.Entry(blog).Collection(b => b.Posts).LoadAsync(). Через.Query().Where(...)можно загрузить не всю коллекцию, а часть; - ленивая загрузка: пакет
Microsoft.EntityFrameworkCore.Proxies, вызовUseLazyLoadingProxies()иvirtualнавигационные свойства. Удобно, но это прямая дорога к N+1; - фильтрованный Include: в EF Core можно написать
Include(b => b.Posts.Where(p => p.IsPublished).OrderBy(p => p.Date)); - проекция:
Select(b => new { b.Title, Count = b.Posts.Count })часто лучше любогоInclude, потому что читает только нужные колонки.
Про SQL: по умолчанию EF Core собирает всё в один запрос с JOIN. Две коллекции на одном уровне дают декартов взрыв: 10 постов и 20 тегов превращаются в 200 строк на каждый блог. Лечится AsSplitQuery(), тогда каждая коллекция уходит отдельным запросом. Цена: несколько обращений к базе и риск несогласованных данных, если между запросами кто-то успел записать.
Если в проекте классический EF6, синтаксис похож, но Include там из System.Data.Entity, а вместо ThenInclude пишут вложенный Select внутри Include.
Где спотыкаются
Включают ленивую загрузку и перебирают сущности в цикле. На сотне блогов это сто один запрос.
Навешивают Include на запрос, который заканчивается Select в анонимный тип или DTO. EF Core такой Include игнорирует: в результат попадает только то, что указано в проекции.
Подключают несколько коллекций через Include без AsSplitQuery() и получают медленный запрос с огромным объёмом данных.