asp.net – 实体框架如何决定是引用现有对象还是创建新对象?

仅仅为了我的好奇心(以及未来的知识),Entity Framework 5如何决定何时创建新对象而不是引用现有对象?我可能刚刚做错了什么,但似乎我时不时地做一些事情:

using (TestDB db = new TestDB())
{
    var currParent = db.Parents.Where(p => p.Prop == passedProp).FirstOrDefault();
    if(currParent == null) {
         Parent newParent = new Parent();
         newParent.Prop = passedProp;
         currParent = newParent;
    }
    //maybe do something to currParent here
    var currThing = db.Things.Where(t => t.Prop == passedPropTwo).FirstOrDefault();
    currThing.Parent = currParent;
    db.SaveChanges();
}

EF将在数据库中创建一个新的Parent,基本上是currParent的副本,然后将currThing的Parent_ID值设置为该副本.然后,如果我再次这样做(如果已经有两个父母那样),它将不会创建一个新的Parent而是链接到第一个.我真的不明白这种行为,但在玩了一段时间之后就像:

using (TestDB db = new TestDB())
{
    var currParent = db.Parents.Where(p => p.Prop == passedProp).FirstOrDefault();
    if(currParent == null) {
         Parent newParent = new Parent();
         newParent.Prop = passedProp;
         currParent = newParent;
    }
    //maybe do something to currParent here
    var currThing = db.Things.Where(t => t.Prop == passedPropTwo).FirstOrDefault();
    currThing.Parent = db.Parents.Where(p => p.ID == currParent.ID).First();
    db.SaveChanges();
}

似乎解决了这个问题.有什么理由可能会发生这种情况,我应该注意到,或者当时我做这件事的方式有什么奇怪的吗?对不起,我不能更具体地说明确切的代码是什么,我前一段时间遇到过并用上面的代码修复它,所以我没有看到任何理由询问它.更一般地说,EF如何决定是否引用现有项目而不是创建新项目?只是根据ID是否设置?谢谢!

最佳答案 如果您的DBContext的特定实例向您提供该实体的特定实例,那么它将知道它所代表的数据库中的哪些记录以及您对其所做的任何更改将适用于那些(那些)记录在数据库中.如果您自己实例化一个新实体,那么您需要告诉DBContext该记录究竟是什么,除非是应该插入数据库的新记录.

在特殊情况下,您有多个DBContext实例,并且一个实例为您提供此实体,但您希望使用另一个实例来处理并保存实体,那么您必须使用((IObjectContextAdapter)firstDbContext).ObjectContext.Detach()to孤立这个实体,然后使用((IObjectContextAdapter)secondDbContext).ObjectContext.Parents.Attach()来附加它(如果你也在编辑它,则使用ApplyChanges() – 这将为你调用Attach).

在其他一些特殊情况下(您的对象已被序列化和/或您具有自我跟踪实体),可能还需要一些额外的步骤,具体取决于您要做什么.

总而言之,如果您的DBContext的特定实例“了解”您的特定实体实例,那么它将使用它,就像它直接绑定到数据库中的特定行一样.

点赞