Что такое навигационные свойства в Entity Framework
Что проверяют
Понимаете ли вы, как отношения в базе превращаются в объектную модель, и видите ли цену: навигационное свойство это не обычное поле, а потенциальный запрос к базе, о котором в коде ничего не написано.
Как отвечать
Навигационное свойство это ссылка на связанную сущность или коллекция связанных сущностей, по которой Entity Framework знает про связь и умеет подтягивать данные. Рядом обычно держат внешний ключ отдельным свойством: так можно задать связь, не загружая объект, и по допустимости значения null сразу видно, обязательная связь или нет.
public class Book
{
public int Id { get; set; }
public int AuthorId { get; set; }
public Author Author { get; set; } = null!;
}Дальше про загрузку, и тут важна точность:
- жадная:
IncludeиThenIncludeтянут связанные данные тем же запросом; - явная: загрузка по требованию через
Entry(...).Reference(...)илиCollection(...); - ленивая: сама по себе не работает, нужен отдельный пакет прокси и виртуальные навигационные свойства.
Сильный ответ добавит две вещи. При проекции в отдельный тип через Select никакой Include не нужен, запрос сам возьмёт только нужные колонки. А несколько Include по коллекциям дают декартово размножение строк, и лечится это разделением на несколько запросов.
Где спотыкаются
Включают ленивую загрузку и получают запрос на каждую строку списка: обращение к навигационному свойству внутри цикла выглядит как чтение поля, а работает как поход в базу. Без просмотра лога запросов проблему не видно до роста данных.
Ждут, что связанные данные подтянутся сами. Без Include и без прокси навигационное свойство останется пустым, и код падает на обращении к нему. Обратная крайность тоже встречается: Include навешивают на всё подряд и каждым запросом вытягивают половину базы.
Отдают сущности с двусторонними навигационными свойствами прямо наружу, в ответ веб-интерфейса. Получается циклическая ссылка при сериализации и заодно утечка полей, которых в контракте быть не должно.