EF:将实体复杂字段设置为null

时间:2012-03-16 12:45:23

标签: asp.net-mvc entity-framework

实体:

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();

1 个答案:

答案 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期间删除关系。