0

自分のプロジェクトの記事を更新するために私のリポジトリにUpdateメソッドがあります。私は当初、記事の管理編集を実行するためだけにこの方法を使用していました。それは正しく処理されますが、私は「最も読まれた」記事を計算するための簡単なメカニズムを追加したいと考えました。これを行うために、記事を閲覧するたびにTimesReadのプロパティを更新したいと思います。これは、ObjectStateManager.ChangeObjectStateを使用して周りを回っているように見えるアップデートで私に問題を与えています。ここに私のUpdate方法です:私のAdminControllerMVC3:リポジトリのアップデートとObjectStateManager

public void Update(Article article) 
{ 
    if (article == null) return; 

    db.Articles.Attach(article); 
    db.ObjectStateManager.ChangeObjectState(article, EntityState.Modified); 
    db.SaveChanges(); 
} 

は、以下の方法が正しく更新されます

[HttpPost] 
public ActionResult Edit(AdminEditViewModel viewModel) 
{ 
    if (ModelState.IsValid) 
    { 
     Article article = Mapper.Map<AdminEditViewModel, Article>(viewModel); 
     articleRepository.Update(article); 

     return RedirectToAction("Index"); 
    } 

    viewModel.Categories = new SelectList(categoryRepository.GetAll(), "CategoryID", "Name", viewModel.CategoryID); 

    return View(viewModel); 
} 

しかし、TimesReadシナリオでは、更新がの例外トリガします:

オブジェクトがすでにオブジェクトコンテキスト内にあるため、オブジェクトを追加できません。オブジェクトは、変更されていない状態のときにのみ再接続できます。そのコントローラのメソッドから

関連するコードは:

var model = articleRepository.GetByID(id); 

model.TimesRead++; 
articleRepository.Update(model); 

return View(model); 

私はこれを解決するために何ができるかを確認するために周りを見た後、私はthis SOの質問に答えに出くわしました。そこで私はUpdateメソッドをコードを提案したものに置き換えてその答えを実装しました。これは私の管理シナリオでは正しく動作しますが、TimesReadシナリオでは正しく動作しません。次の例外がスローされます。

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

例外は意味がはっきりしていますが、私はこれらのような簡単なアップデートをどのように扱うべきか疑問に思っています。私は、EntityState.Unchangedを設定してモデルが変更されずにTimesReadに更新されますが、ObjectStateManagerにオブジェクトへの参照が保持されていないことを示す管理者の更新は例外であるとEFを "欺く"ことができます。

これらのシナリオがどのように異なっているかは明らかです。 Editアクションは、ViewModelのプロパティを新しい添付されていないArticleオブジェクトにマッピングしますが、ArticleControllerはコンテキストから直接取得されたオブジェクトを処理します。それは、私がそれらのコントローラメソッドの1つをリファクタリングする必要があるという気持ちで私を残すので、更新するために取られたステップは同じです。私は両方のアプローチが私に共存できるように見えるので、どのようにアプローチしなければならないのかは分かりません。だから私の質問は、正しく動作するように両方のタイプのアップデートを取得するために何を変更できますか?

あなたのお時間をいただきありがとうございます。投稿されたコードの量は本当に申し訳ありません。私はそれがすべて問題に関連していると感じています。

+0

DBコンテキストをどのようにインスタンス化していますか?あなたの更新メソッドはそれをやっていないようです。 –

+0

これは 'ArticleRepository'クラス内のプライベートメンバーなので、リポジトリが構築されるとすぐにインスタンス化されます。 'ArticleRepository.Update'は問題のメソッドです。申し訳ありませんが、私はそれを十分に明確にしませんでした。 –

+0

そして、どのようにあなたのArticleRepositoryを構築していますか?私の指摘は、HTTPはステートレスなので、要求を越えてDBコンテキストへの参照を保持することはできません。だから、あなたの問題がdbコンテキストの古いコピーによって引き起こされていないことを確認しています。 –

答えて

0

2つの方法の主な違いは、Admin EditメソッドがAdminEditViewModelから新しいアーティクルを作成し、この新しく作成されたアーティクルをデータベースに添付することです。これは、DCには一度も接続されていない新しいオブジェクトだからです。

2番目のケースでは、リポジトリからアーティクルを取得し、そのアーティクルを更新してから再度アタッチします。これは新しく作成されたアーティクルではないため失敗します。すでに添付されています。それをもう一度付けようとしています。

+0

私はこれを理解していますが、私はそれについて何をしますか? 'Edit'メソッドを' Article article = articleRepository.GetByID(id); 'のようなものにリファクタリングしてViewModelを代わりにその記事オブジェクトにマッピングする必要がありますか?必要なすべての情報がViewModelに既にある場合、オブジェクトを照会するのはちょっと奇妙なようです。 –

+0

Re:上記の私のコメント、私はちょうどそれを試み、それは違いはありません。しかし、それはあなたが上で述べたように、要求の間にコンテキストが構築される方法を説明しましたが、今は本当にそれを解決する方法がわかりません。これまでのところ助けてくれてありがとう。 –

+1

@johnh - いくつかの解決策があります。たとえば、記事をリポジトリから取得した後、その記事を切り離すことができます。しかし、私は全体的により良いソリューションを設計したいと思っています。それは、ここに掲載するよりもデザインについて多くのことを知る必要があります。 –

関連する問題