Чтобы получить ленивую загрузку для вашей детской коллекции, должны быть выполнены два требования:
- Родительский объект должен быть присоединен к контексту EF
- Ваш родительский объект должен быть ленивым загрузочным прокси
Оба требования выполняются, если вы загружаете родительский объект из базы данных через контекст (и ваши свойства навигации virtual
для разрешения создания прокси).
Если вы не загружаете объект из базы данных, а создаете его вручную, вы можете достичь того же, используя соответствующие функции EF:
var parent = context.TestParents.Create();
parent.TestParentID = 1;
context.TestParents.Attach(parent);
Здесь важно использовать Create
, а не new
, поскольку оно создает требуемый ленивый загрузочный прокси. Затем вы можете получить доступ к дочерней коллекции, и потомки родителей с ID = 1 будут загружены лениво:
var children = parent.TestChildren; // no NullReferenceException
Теперь связыватель моделей по умолчанию не имеет ни малейшего представления об этих конкретных функциях EF и просто создает экземпляр родительского элемента с помощью new
, а также не присоединяет его к какому-либо контексту. Оба требования не выполнены, и отложенная загрузка не работает.
Вы можете написать свой собственный связыватель модели для создания экземпляра с Create()
, но это, вероятно, худшее решение, так как это сделает ваш видовой слой очень зависимым от EF.
Если вам нужна дочерняя коллекция после привязки модели, я бы в этом случае загрузил ее через явную загрузку:
// parent comes as parameter from POST action method
context.TestParents.Attach(parent);
context.Entry(parent).Collection(p => p.TestChildren).Load();
Если ваш контекст и EF скрыты за хранилищем, вам потребуется новый метод хранилища, например:
void LoadNavigationCollection<TElement>(T entity,
Expression<Func<T, ICollection<TElement>>> navigationProperty)
where TElement : class
{
_context.Set<T>().Attach(entity);
_context.Entry(entity).Collection(navigationProperty).Load();
}
... где _context
является членом класса репозитория.
Но лучший способ, как упоминал Дарин, - это связать ViewModels и затем привязать их к вашим сущностям по мере необходимости. Тогда у вас будет возможность создать экземпляры сущностей с помощью Create()
.