0

Entity Framework 4.0 を使用しています。データベースのデータを更新しているときに問題に直面しています。この例外が発生しています:

同じキーを持つオブジェクトが ObjectStateManager に既に存在します。
ObjectStateManager は、同じキーを持つ複数のオブジェクトを追跡できません。

私はリレーショナルデータベースに取り組んでいます。以下は 3 つのエンティティであり、関係があります。

         1    to   *        1   to    *
Ceremony -----------> Menu ------------> CourseOption

Menus既にand を含むセレモニーを更新すると、すべて正常に動作しCourseOptionsます。問題は、更新時にセレモニーにnewMenuとentryを挿入するときに発生します。CourseOption上記の例外が発生しました。

既存のセレモニーを更新する C# コード

public HttpResponseMessage PutCeremony(int id, Ceremony ceremony)
{
    if (ModelState.IsValid && id == ceremony.Id)
    {
       db.Entry(ceremony).State = EntityState.Modified;

       try
       {
           db.SaveChanges();
       }
       catch (DbUpdateConcurrencyException)
       {
           return Request.CreateResponse(HttpStatusCode.NotFound);
       }

       return Request.CreateResponse(HttpStatusCode.OK, ceremony);
    }
    else
    {
       return Request.CreateResponse(HttpStatusCode.BadRequest);
    }
}

どうすればこの問題を解決できますか? 助けてください

編集

今日、私はこれで一日を過ごし、多くのアーティカルとスタックオーバーフローの質問を読みました。私はそれを見つけたonce a product is fetched from the Context, the context is keeping track of itので、代わりに使用するのはなぜですか:

db.Entry(ceremony).State = EntityState.Modified;

使った

db.Entry(db.Ceremonies.Find(ceremony.Id)).CurrentValues.SetValues(ceremony);

この変更を行うと、例外がなくなり、Ceremony エンティティのプロパティが適切に変更されます。ただし、セレモニー関連の Menus エントリと CourseOptions エントリは更新されていません。提案をお願いします。私はEFでまったく新しいです。

4

1 に答える 1

1

切り離されたオブジェクト グラフの更新は、非常に困難な場合があります。(子コレクションが 1 つだけの例はこちら: https://stackoverflow.com/a/5540956/270591孫コレクションがある場合は、さらに複雑になります。)

Modified状態を に設定し(スカラー プロパティを変更済みとしてマークするだけです)、すべてのオブジェクト グラフの変更を保存することを期待するような、一般的なアプローチや単純な方法はありません。

このような更新を実装するために考慮すべき詳細:

  • ユーザーは、セレモニーにメニューが追加されたときに新しいメニューを作成しますか?それとも、セレモニーと既存のメニューの間の関係を確立するだけですか?
  • メニューがセレモニーから削除されたときに、ユーザーは既存のメニューを削除しますか、それともセレモニーとメニューの間の関係のみを解放しますが、メニューはデータベースにまだ存在している必要があります (その場合、FK は null 可能である必要があります)。
  • ユーザーはビューで (スカラー) メニュー プロパティを変更できますか? それとも、メニュー自体を変更せずにセレモニーにメニューを追加したり削除したりできますか?
  • CourseOptions同じ質問が、各の孫コレクションにも当てはまりますMenu

特定のセレモニー編集ビューのユーザーがいる(比較的単純な)ケースの場合...

  • セレモニーのスカラー プロパティを変更できます
  • 既存のメニューを削除するときにデータベースから削除する必要があるセレモニーから既存のメニューを削除でき、関連CourseOptionsするものも削除する必要があり、データベースでその関係のカスケード削除が有効になっています
  • データベースに挿入するセレモニーに新しいメニューを作成および追加できます
  • 既存のメニューのスカラー プロパティを変更できません
  • CourseOptions既存のに追加するMenuことも、から削除することもできませんMenu
  • CourseOptionsnewに new を追加できますMenu(CourseOptions新しいメニューと一緒に挿入する必要があります)。
  • 既存のスカラー プロパティを変更できませんCourseOption

...コードは次のようになります。

var ceremonyInDb = db.Ceremonies.Include(c => c.Menus)
    .Single(c => c.Id == ceremony.Id);

db.Entry(ceremonyInDb).CurrentValues.SetValues(ceremony);

foreach (var menuInDb in ceremonyInDb.Menus.ToList())
    if (!ceremony.Menus.Any(m => m.Id == menuInDb.Id))
        db.Menus.Remove(menuInDb);

foreach (var menu in ceremony.Menus)
    if (!ceremonyInDb.Menus.Any(m => m.Id == menu.Id))
        ceremonyInDb.Menus.Add(menu);

db.SaveChanges();

一部の制限が適用されない場合 (つまり、ユーザーがビューでより複雑な変更を行うことができる場合)、コードはより複雑になります。ただし、基本的な考え方は、データベースからオブジェクト グラフ (ルートと子、Includeおよび場合によっては孫Include(...Select(...))) をロードし、その元のグラフを新しい切り離されたグラフと比較し、新しいグラフとの違いに従って元のグラフに変更を適用することです。

于 2012-10-29T18:55:55.013 に答える