为什么不能使用导航参考将新对象附加到跟踪对象?

时间:2013-06-07 13:54:53

标签: c# .net entity-framework-4 dbcontext

简而言之,为什么这会失败(myChildObject 添加到数据库中)。 请注意,它适用于ObjectContext

using (var db = new dbEntities())
{
    var myParentObject = db.parentObjects.First(); // this definitely exists in the db

    // this **should** attach myChildObject to the context, 
    // and therefore add it to the db on .SaveChanges() - it doesn't!
    var myChildObject = new childObject(){
        parentObject = myParentObject
    };

    db.SaveChanges();
}

This MSDN Blog Post

  

您可以通过将新实体连接到已经被跟踪的另一个实体来将新实体添加到上下文中。这可以通过将新实体添加到另一个实体的集合导航属性中,或者通过将另一个实体的引用导航属性设置为指向新实体来实现。

以上代码当然应该有效,因为myChildObject引用了myParentObject这是一个跟踪对象。 EF应足够聪明,以确定它需要添加到childObjects集合中。当我使用ObjectContext时它工作正常,现在我发现我需要重写所有代码以使其与dbContext一起使用。

要使它工作,我必须像这样重写它:

using (var db = new dbEntities())
{
    var myParentObject = db.parentObjects.First(); // this definitely exists in the db

    var myChildObject = new childObject();

    myParentObject.childObjects.Add(myChildObject);

    db.SaveChanges();
}

2 个答案:

答案 0 :(得分:1)

如果您使用的是带有ObjectContext的POCO实体,那确实有效。但不是因为EF的更改跟踪与DbContext的工作方式不同,而是因为EF 4 T4模板生成的POCO实体包含“关系修正”方法。

基本上,行parentObject = myParentObject的属性设置器不仅是一个对象赋值,而且setter包含对方法的调用,该方法最终完全按照您现在手动执行的操作,即:{{1} }。此时规则“您可以通过将新实体连接到已经被跟踪的另一个实体来将新实体添加到上下文中,并且myParentObject.childObjects.Add(myChildObject)被添加到上下文并插入到数据库。

对于为myChildObject生成POCO实体的T4模板,这些修复方法已被删除,因为它们在其他方案中引起了麻烦。特别是当涉及延迟加载时,您的引用分配和属性设置器中DbContext的自动调用将触发对集合的延迟加载,并首先加载已为myParentObject.childObjects...存储的所有childObjects新的孩子被添加到集合中。如果这些是数以千计,这是一个巨大的不必要的开销,性能变得灾难性的,并且如果您不知道后面运行的修复方法,那么突然性能不佳的原因(仅因为您分配了单个引用属性)并不容易检测到场景。

Herehere以及herehere是关系修正方法引起混淆的示例。

可以修改T4模板并再次添加关系修复方法 - 或者如果你使用Code-First只是在你的实体类中手工编写它们 - 来恢复旧的行为。但这可能比你在上一个代码片段中概述的方式改变现有代码要复杂得多,至少也是如此:我当然更愿意回过头来解决那些麻烦的修复方法。

答案 1 :(得分:0)

@theyetiman你正在对博客文本做一点解释错误。

请参阅:

  

[...]
  或者通过设置另一个实体的引用导航属性来指向新实体。

在这部分中,博客说你可以用新实体设置被跟踪对象的引用导航属性。

像这样:

  

[tracked entity] .NavigationProperty = [new entity];

但是你要做:

  

[new entity] .Navigation Property = [tracked entity];

这不起作用。如果跟踪了childObject而没有parentObject,则可以在childObject属性中添加parentObject设置它,但反之则不然。