实体:
public class Page
{
//...
public virtual Page Parent { get; set; }
}
需要将Parent字段设置为null。试过这个,但没有运气:
// Existing entity
Page pageAttached = db.Pages.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();
答案 0 :(得分:2)
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)
。我更喜欢使用lambda重载进行强类型输入。将魔术字符串保留在代码之外。
这可行的原因是因为DbContext使用动态生成的代理类进行延迟加载。当您只查询.First(x => x.Id == page.Id)
时,返回的对象实际上是一个实现Page
实体作为其基类的类。 (这就是为什么必须将集合和导航属性标记为virtual
,因此可以在动态代理中覆盖它们。)此外,动态生成的代理具有空父引用,即使数据库中存在父代也是如此。 。
直到调用Parent属性get方法,EF才会命中db来懒惰加载父级。这是当它发现db实际上是否具有null或非null Parent属性时。因此,当您在父实际上延迟加载之前设置.Parent = null
时,EF不执行任何操作,因为它已经为空。
我建议的代码使用.Include
急切加载 Parent属性。这意味着db在单个db调用中同时获取子级+父级。现在,当您设置null时,DbContext将跟踪更改并在下一次SaveChanges期间删除关系。