Ответ
Это три стратегии загрузки связанных данных (навигационных свойств) в Entity Framework Core, каждая со своей семантикой и временем выполнения.
1. Жадная загрузка (Eager Loading)
Данные загружаются одним запросом вместе с основными сущностями, используя метод Include (и ThenInclude).
// Все данные (Blog, Posts, Author каждого Post) загружаются одним SQL-запросом с JOIN.
var blog = context.Blogs
.Include(b => b.Posts) // Загружаем связанные посты
.ThenInclude(p => p.Author) // Загружаем автора каждого поста (вложенное свойство)
.FirstOrDefault(b => b.Id == 1);
Плюсы: Предсказуемость (1 запрос), данные доступны сразу. Минусы: Может привести к избыточному объему данных (over-fetching) и сложным запросам при глубокой вложенности.
2. Ленивая загрузка (Lazy Loading)
Связанные данные загружаются автоматически и прозрачно при первом обращении к навигационному свойству, но для этого требуется:
- Установка пакета
Microsoft.EntityFrameworkCore.Proxies. - Включение вызовом
UseLazyLoadingProxies()вOnConfiguring. - Объявление навигационных свойств как
virtual.
public class Blog
{
public int Id { get; set; }
public virtual ICollection<Post> Posts { get; set; } // Виртуальное свойство
}
// ... в коде
var blog = context.Blogs.First(b => b.Id == 1); // Запрос 1: SELECT * FROM Blogs
foreach (var post in blog.Posts) // Запрос 2: SELECT * FROM Posts WHERE BlogId = 1
{
Console.WriteLine(post.Title); // Данные подгружены "лениво"
}
Плюсы: Удобство, код не загроможден Include. Загружаются только нужные в момент обращения данные.
Минусы: Риск проблемы N+1: для N основных сущностей выполняется N+1 отдельных запросов к БД, что убивает производительность.
3. Явная загрузка (Explicit Loading)
Разработчик вручную указывает, когда и какие связанные данные нужно загрузить, используя методы Load() для коллекций или Reference() для одиночных свойств.
var blog = context.Blogs.First(b => b.Id == 1); // Запрос 1: загружаем блог
// ЯВНО загружаем посты, когда они нужны
context.Entry(blog)
.Collection(b => b.Posts)
.Load(); // Запрос 2: SELECT * FROM Posts WHERE BlogId = 1
// Теперь blog.Posts заполнена и доступна
Плюсы: Полный контроль над временем и условиями загрузки. Позволяет загружать данные условно. Минусы: Более многословный код.
Рекомендация по выбору: Для большинства сценариев, где структура запроса известна заранее, жадная загрузка (Include) является предпочтительной, так как она эффективна и предсказуема. Ленивую загрузку следует использовать с крайней осторожностью, явно осознавая риск N+1.