11

POCOの可能性に興味があるので、EF 4.0をいじり始めました...切断されたWeb環境をシミュレートしたいと思い、これをシミュレートするために次のコードを記述しました。

  1. テストオブジェクトをデータベースに保存します。
  2. テストオブジェクトを取得します
  3. 取得に使用したテストオブジェクトに関連付けられたDataContextを破棄します
  4. テストオブジェクトを更新します
  5. 新しいデータコンテキストを作成し、POCOオブジェクトに対して生成されたDynamicProxy内で自動的に追跡されるテストオブジェクトの変更を永続化します。

問題は、上記のTestメソッドでdataContext.SaveChangesを呼び出すと、更新が適用されないことです。testStoreエンティティは、EntityStateTrackerを確認すると「変更済み」のステータスを示しますが、新しいdataContextのStoresプロパティ内で表示すると変更されなくなりました。新しいdataContextでAttachメソッドを呼び出すと、オブジェクトの「変更済み」状態も回復すると思いましたが、そうではないようです。足りないものはありますか?私は間違いなくDynamicProxiesを使用して自己追跡POCOを使用しています。

private static void SaveTestStore(string storeName = "TestStore")
{
  using (var context = new DataContext())
  {
    Store newStore = context.Stores.CreateObject();
    newStore.Name = storeName;
    context.Stores.AddObject(newStore);
    context.SaveChanges();
  }
}

private static Store GetStore(string storeName = "TestStore")
{
  using (var context = new DataContext())
  {
    return (from store in context.Stores
            where store.Name == storeName
            select store).SingleOrDefault();
  }
}

[Test]
public void Test_Store_Update_Using_Different_DataContext()
{
  SaveTestStore();
  Store testStore = GetStore();
  testStore.Name = "Updated";      

  using (var dataContext = new DataContext())
  {
    dataContext.Stores.Attach(testStore);
    dataContext.SaveChanges(SaveOptions.DetectChangesBeforeSave);        
  }

  Store updatedStore = GetStore("Updated");
  Assert.IsNotNull(updatedStore);
}
4

4 に答える 4

8

後で述べたように、自己追跡エンティティ ジェネレーターではなく、POCO ジェネレーターを使用していました。

私もそれを試してみましたが、かなり困惑しました。プロキシ クラスが期待どおりに機能していないようで、バグがある可能性があります。また。MSDN の例はどれもこのようなことを試みておらず、アプリのさまざまな層で更新を参照する場合 (ここで行っているようなこと)、POCO プロキシではなく自己追跡エンティティを使用します。

これらのプロキシがどのように機能するかはわかりませんが、ある種の状態を保存しているようです (プライベート プロパティ内で「変更済み」状態を見つけることができました)。しかし、このプロパティは完全に無視されているようです。プロパティをコンテキストにアタッチすると、コンテキストは ObjectStateManager にエントリを追加し、さらに状態の更新をそこに保存します。この時点で変更を行うと、変更が登録され、適用されます。

問題は、エンティティを .Attach すると、プロキシからの Modified 状態がコンテキスト内の状態マネージャーに転送されないことです。さらに、 context.Refresh() を使用すると、更新が上書きされ、忘れられます! RefreshMode.ClientWins を渡しても。オブジェクトの状態の状態プロパティを変更済みに設定しようとしましたが、とにかく上書きされ、元の設定が復元されました..

EF には正しくないバグがあるようです。これを行う唯一の方法は、次のようなものを使用することです。

using (var db = new Entities())
{
    var newUser = (from u in db.Users
                    where u.Id == user.Id
                    select u).SingleOrDefault();
    db.Users.ApplyCurrentValues(user);
    db.SaveChanges();
}

ここでもう一つ

Entity Framework: POCO アプローチによる SOA での変更追跡

POCOはあなたが探しているアプローチをサポートしていないようです.POCOのプロキシは、作成したコンテキスト内でのみ変更を追跡します..またはそうらしい、それっぽい...

于 2010-04-22T06:22:34.147 に答える
5

試す

        db.ObjectStateManager.ChangeObjectState(user, System.Data.EntityState.Modified);

SaveChanges を呼び出す前に

于 2010-05-26T00:57:00.507 に答える
2

自己追跡エンティティで遊んだ後、私はあなたの間違いに気づきました。エンティティをデータ コンテキストにアタッチするのではなく、データ コンテキストに対して、エンティティに加えた新しい変更をデータベースに適用するように指示する必要があります。

この場合、「保存」コードを次のように変更します。

using (var dataContext = new DataContext())
{
    dataContext.Stores.ApplyChanges(testStore);
    dataContext.SaveChanges();        
}

少なくともローカル マシンでテストしたところ、この更新後に機能しました :)
これが役に立てば幸いです。

于 2010-04-21T19:59:38.797 に答える
0

あなたの問題の根源は Context オブジェクトの管理だと思います。

POCO を使用すると、コンテキストを破棄しても、そのコンテキストのエンティティに、エンティティがコンテキストに関連付けられなくなったことは通知されません。POCO を使用した変更追跡はすべてコンテキストによって管理されるため、POCO がまだコンテキストにアタッチされているように動作するが、実際にはそうではなく、別のコンテキストに再アタッチすると、アタッチに関するエラーがスローされるという楽しい問題が発生します。複数のコンテキストに。

これについては、ここで読みたい小さな投稿があります。

セルフ トラッキングに切り替えると、エンティティが希望どおりに機能することがわかると思います。

もう 1 つのオプションは、poco の部分クラスにプロパティを追加して、POCO をロードに使用したコンテキストから切り離した後、変更を手動で追跡することです。

于 2010-10-14T14:27:34.123 に答える