Parent
это не «сложное поле», это «Свойство навигации».
Работает ли это, если вы это делаете?
// Existing entity
Page pageAttached = db.Pages.Include(x => x.Parent).First(x => x.Id == page.Id);
db.Entry(pageAttached).CurrentValues.SetValues(page);
if (model.ParentId != null)
pageAttached.Parent = db.Pages.First(x => x.Id == model.ParentId);
else
pageAttached.Parent = null; //does nothing
db.SaveChanges();
Ответ на комментарий 1
Нет, я имел в виду .Include(x => x.Parent)
.Я предпочитаю строго печатать с использованием перегрузки лямбда.Хранит магические строки в коде.
Причина, по которой это работает, заключается в том, что DbContext использует динамически сгенерированные прокси-классы для отложенной загрузки.Когда вы запрашиваете только .First(x => x.Id == page.Id)
, возвращаемый объект действительно является классом, который реализует вашу сущность Page
в качестве ее базового класса.(Вот почему свойства коллекции и навигации должны быть помечены virtual
, чтобы их можно было переопределить в динамических прокси.) Кроме того, динамически сгенерированный прокси имеет нулевую ссылку Parent, даже если в db есть родительский объект.
Только когда метод get свойства Parent вызывается, EF нажимает на базу данных, чтобы лениво загрузить родителя.Это когда он узнает, действительно ли БД имеет нулевое или ненулевое свойство Parent.Поэтому, когда вы устанавливаете .Parent = null
до того, как родительский объект фактически загружен, EF ничего не делает, потому что он уже равен нулю.
Код, который я предложил, использует от .Include
до eager load свойство Parent,Это означает, что БД получает и дочерний элемент, и его родителя за один вызов БД.Теперь, когда вы установите значение NULL, DbContext будет отслеживать изменения и удалять отношения во время ваших следующих SaveChanges.