实体框架:ChildCollection项目删除

时间:2012-04-27 13:50:10

标签: entity-framework-4

鉴于这种关系:

  

人1 - * TelephoneNumber

     

(一个人有0个,1个或更多个TelephoneNumber实体)

我的集成测试:

    [TestMethod()]
    public void DeleteTelephoneNumberAndSavePersonTest()
    {
        Person person;
        using (SopEntities sopEntities = EntitiesFactory.Create(Properties.Resources.ConnectionString))
        {
            PeopleRepository target = new PeopleRepository(sopEntities);
            person = target.GetPerson(7);
            Assert.IsTrue(person.TelephoneNumbers.Any());
            Assert.AreEqual("DeleteTelephoneNumberAndSavePersonTest", person.TelephoneNumbers.Single().Number);
            person.TelephoneNumbers.Remove(person.TelephoneNumbers.Single());
            target.SavePerson(person);

            Person savedPerson = target.GetPerson(7);
            Assert.IsFalse(savedPerson.TelephoneNumbers.Any());
        }
    }

获取已创建的(我知道这是真的)Person(ID = 7),其TelephoneNumbers集合中有一个TelephoneNumber。这很好。

然后我删除了TelephoneNumber作为我测试的一部分。

并保存,使用以下代码:

    public Person SavePerson(Person person)
        {
            if (person == null)
                throw new ArgumentNullException("person");


            Person existingPerson= SopEntities.People.Include("EmailAddresses").Include("TelephoneNumbers").Include("WebResources").SingleOrDefault(q => q.ID==person.ID);
// NOTE: The existingPerson ALREADY has the TelephoneNumber removed, even though retrieved from the DB again. WHY IS THIS?

// snip: collection reconciliation code

            SopEntities.SaveChanges();
            return existingPerson;
        }

我不想在这一点上通过内存与持久收藏的协调来分散这篇文章的注意力,但是我想引起你对现有版本的现代版本的关注。当我通过调试时,此人已经从其TelephoneNumbers集合中删除了TelephoneNumber。

这样做的原因是它在TestMethod中的相同Entities上下文中。如果我在加载TelephoneNumber和删除项目之间创建新的上下文,则检索到的Person确实在TelephoneNumbers集合中具有预期的TelephoneNumber,以便在适当的时候删除。

EntityFramework显然缓存了这一变化,并且“为了更好的词语”而“预测”了内部情境的变化。我不希望这种情况发生。

如何防止此行为?即。当我要求数据库内容时,我想要数据库内容而不是EF对数据库内容的印象。

1 个答案:

答案 0 :(得分:0)

您可以尝试在此行中加载此人...

Person existingPerson= SopEntities.People....
    .SingleOrDefault(q => q.ID==person.ID);

...已禁用更改跟踪(对AsNoTracking()使用DbContextMergeOption.NoTracking使用ObjectContext)以避免EF尝试将实体附加到您的上下文已修改过它。

如果您想使用从SavePerson返回的对象进行更改跟踪并希望将其附加到上下文,这可能毫无用处。 EF不允许两个具有相同键的附加对象,它将返回已附加的对象,包括您已应用于实体的所有修改。

我不知道你想要达到什么目标。看起来有点像你的SavePerson方法应该返回“之前”的人(修改它之前的状态中的人)。如果是这样,另一种方法是在开始修改对象并返回克隆之前(深度)克隆该对象。