Даже при отключенной отложенной загрузке, если DbContext уже отслеживает сущность, на которую вы ссылаетесь, эта ссылка будет заполнена автоматически.
Например, если у меня есть 2 записи Parent, каждая из которых содержит запись Child:
Parent 1 => Child 1
Parent 2 => Child 2
using (var context = new AppContext())
{
var junk = context.Parents.Single(x => x.ParentId == 2);
var children = context.Children.ToList();
Assert.IsNull(children.Single(x => x.ChildId == 1).Parent);
Assert.IsNotNull(children.Single(x => x.ChildId == 2).Parent);
}
Это очень грубый пример поведения, но junk
представляет dbContext, имеющий загружен и отслеживание родительского идентификатора № 2. В течение срока службы DbContext это может происходить в любом месте до нашего вызова, особенно если время жизни превышает весь запрос. Когда мы позже go найдем наших детей и предположим, что отложенная загрузка отключена, и мы не стремимся загружать их родителей, вы обнаружите, что родительская ссылка Child ID # 1 будет #null, но DbContext будет ассоциировать Parent # 2 с ребенком № 2. Когда контекст заполняет ссылку Child # 2, он видит связь с parent и хочет Parent ID # 2, его локальный кеш отслеживания знает о Parent # 2, поэтому ссылка заполняется автоматически.
Если junk
вместо этого была строка:
var junk = context.Parents.AsNoTracking().Single(x => x.ParentId == 2);
, тогда родительская ссылка дочернего элемента # 2 также была бы #null, поскольку DbContext не отслеживал бы эту родительскую ссылку.
Это может привести ко всем видам причудливое поведение по мере того, как приложения развиваются, и новый код вводится или пересматривается. Все, что нужно, это добавить кого-то AsNoTracking()
в качестве «оптимизации производительности», а какое-то поведение, которое ранее ссылалось на что-то, теперь не работает.
Как правило, чтобы избежать осложнений, я рекомендую никогда вернуть Entities за пределы DbContext, который их породил, и вместо этого полагаться на ViewModels или DTO для представления данных, которые вы хотите передать в представление или вернуть потребителю API, вместо того, чтобы пытаться выборочно заполнять объекты для этой цели. Сущность всегда должна отражать полное состояние данных, либо заполнив все свои данные, либо все данные доступны (через прокси). Когда незавершенные сущности передаются, в конечном итоге они попадают в методы, которые ожидают завершенные сущности (основанные на сигнатуре метода), и это приводит к проблемам, когда предполагается, что данные являются полными, но источник этой сущности не заполнен.