0

与えられた関係:

個人 1 -- * 電話番号

(個人には 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());
        }
    }

これは、TelephoneNumbers コレクションに単一の TelephoneNumber を持つ、既に作成されている (これが正しいことを知っている) Person (ID=7) を取得します。これはうまくいきます。

次に、テストの一環として 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;
        }

この時点で、インメモリから永続化されたコレクションへの調整でこの記事の注意をそらしたくはありませんが、existingPerson のトリビュールに注意を向けたいと思います。これをデバッグすると、この人はすでに TelephoneNumbers コレクションから TelephoneNumber を削除しています。

これは、TestMethod の同じエンティティ コンテキスト内にあるためです。TelephoneNumber の読み込みとアイテムの削除の間に新しいコンテキストを作成すると、取得された Person には、やがて削除される TelephoneNumbers コレクションに予期される TelephoneNumber が含まれます。

EntityFramework は明らかに変更をキャッシュしており、変更を内部コンテキストに "投影" (より適切な言葉が必要なため) しています。私はこれが起こることを望んでいません。

どうすればこの動作を防ぐことができますか? すなわち。データベースの内容を尋ねるとき、DB の内容に対する EF の印象ではなく、データベースの内容が必要です。

4

1 に答える 1

0

この行に人をロードしてみることができます...

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

...変更の追跡を無効にして(AsNoTracking()forDbContextおよびMergeOption.NoTrackingforを使用ObjectContext)、EFがエンティティを既に変更したコンテキストにアタッチしようとするのを回避します。

SavePersonから返されたオブジェクトを変更の追跡に使用し、それをコンテキストにアタッチしたい場合、これは役に立たない可能性があります。EFは、同じキーを持つ2つのアタッチされたオブジェクトを持つことを許可せず、エンティティにすでに適用されたすべての変更を含む、すでにアタッチされたオブジェクトを返します。

あなたが何を達成したいのかわかりません。SavePersonメソッドが「前の」人(変更前の状態の人)を返すことになっているように見えます。その場合、別のアプローチは、オブジェクトの変更を開始してクローンを返す前に、オブジェクトを(ディープ)クローンすることです。

于 2012-04-27T17:00:03.790 に答える