2011-10-18 7 views
5

まず、エンティティフレームワークのコードを使用して、northwindデータベースをWCF REST HTTPインターフェイスで公開しています。エンティティグラフを再接続してコレクションの変更を検出する

私はOrderDetailsテーブル(注文アイテム)を公開していません。注文を作成してから、必要なOrderDetailを別のサービスに別々に追加することは意味がありません。私の考えでは、成功するか失敗するかのどちらかの原子的なトランザクションである必要があります。したがって、クライアントに渡すときにOrder.OrderDetailsコレクションを含め、注文が作成または更新されたときに取得すると仮定します。

しかし、問題は、更新のOrderエンティティを再接続するときに、OrderDetailsコレクションの変更を検出しているようです。オーダー自体は、これらのプロパティーを更新するために変更されたものとして設定できますが、これはOrderDetail項目にカスケードしません。だから私は手動で行って、更新されたものを修正するように設定することができますが、問題は最初に更新されるものを見つけることにあります。新しいOrderDetailを変更すると、保存しようとするとエラーが発生します。

新しいコレクションアイテムのIDを0に設定するという推奨事項を読んで、サーバーでそれを使用して新しいコレクションアイテムが存在するかどうかを判断します。ただし、NorthwindはOrderDetailsにOrderIDとProductIDの複合キーを使用します。これらは両方ともクライアントによって設定されなければならないので、私は新しいものを検出する方法を見つけることができません。さらに、削除されたOrderDetailは切り離されたグラフには存在しないので、削除されたものを見つけ出し、明示的に削除する必要があります。

アドバイスをいただければ幸いです。

public override Order Update(Order entity) 
{ 
    dbset.Attach(entity); 
    DataContext.Entry(entity).State = EntityState.Modified; 

    foreach (var orderDetail in entity.OrderDetails) 
    { 
     DataContext.Entry(orderDetail).State = EntityState.Modified; 
    } 

    return entity; 
} 

答えて

4

これはcommon and complex issueであり、あなたのために行う魔法はありません。私の解決策(およびすべてのシナリオでのみ動作1)あなたのアップデート方法で再びOrderをロードして、手動で変更をマージしました:

public override Order Update(Order entity) 
{ 
    // No attach of entity 

    var attached = DataContext.Orders.Include(o => o.OrderDetails).SingleOrDefault(...); 
    if (attached == null) ... 

    // Merge changes from entity to attached - if you change any property 
    // it will be marked as modified automatically 

    foreach (var detail in attached.OrderDetails.ToList()) 
    { 
     // ToList is necessary because you will remove details from the collection 

     // if detail exists in entity check if it must be updated and set its state 

     // if detail doesn't exists in entity remove if from collection - if it is \ 
     // aggregation (detail cannot exists without Order) you must also delete it 
     // from context to ensure it will be deleted from the database 
    } 

    foreach (var detail in entity.OrderDetails) 
    { 
     // if it doesn't exists in attached create new detail instance, 
     // fill it from detail in entity and add it to attached entity - 
     //you must not use the same instance you got from the entity 
    } 

    DataContext.SaveChanges(); 

    return entity; 
} 

また、あなたがそれらを使用する場合、手動でタイムスタンプをチェックする必要がある場合もあります。

代替シナリオは、新しい詳細には0、削除された詳細にはマイナスIDを使用して説明したものですが、これはクライアントで実行する必要があるロジックです。また、場合によってのみ動作します。

+0

偉大な答えです。時間をいただきありがとうございます! –

+0

EFチームがエンティティグラフを添付してもう少し自動化するシナリオを追求しないことにした理由を考えていないとしますか?私はそれがクライアントが更新することを望んでいないと考えていると思っています。Order in Product - OrderItem - Productシナリオを言います。 –

+0

私はこの問題についてもっと考えるほど、完全な自動化は不可能であるか信頼性がないと信じています(信頼性は正確に記述したもので、自動更新によって変更したくないエンティティが変更される可能性があります)。 –

6

私は最近、私が私の雇用主のためにやった仕事のいくつかをオープンソースに許可しました。私は実際にこの問題を解決する拡張メソッドを書いた、あなたはそれを得ることができるhttp://refactorthis.wordpress.com/2012/12/11/introducing-graphdiff-for-entity-framework-code-first-allowing-automated-updates-of-a-graph-of-detached-entities/

それは助けてくれることを願っています!

関連する問題