我的存储库中有一个Update
方法,用于更新项目中的文章。我最初使用这种方法只是为了对文章进行管理员编辑。它可以正确处理,但我决定添加一个简单的机制来计算“阅读次数最多”的文章。为此,我想在TimesRead
每次查看文章时更新属性。这给我带来了似乎围绕使用ObjectStateManager.ChangeObjectState
. 这是我的Update
方法:
public void Update(Article article)
{
if (article == null) return;
db.Articles.Attach(article);
db.ObjectStateManager.ChangeObjectState(article, EntityState.Modified);
db.SaveChanges();
}
在我AdminController
的以下方法中正确更新:
[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);
在环顾四周,看看我能做些什么来解决这个问题后,我发现了这个SO question 的答案。Update
所以我通过用建议的代码替换我的方法来实现这个答案。这在我的管理场景中也可以正常工作,但在场景中却不行TimesRead
。抛出以下异常:
ObjectStateManager 中已存在具有相同键的对象。ObjectStateManager 无法跟踪具有相同键的多个对象。
例外的含义很清楚,但它确实让我想知道我应该如何处理这些简单的更新。我发现我可以“愚弄” EF 认为模型通过设置没有改变,EntityState.Unchanged
并且会更新TimesRead
,但会为管理员更新提供例外,说明ObjectStateManager
不包含对对象的引用。
我也很清楚这些场景有何不同。该Edit
操作是将 ViewModel 中的属性映射到一个新的、未附加的Article
对象上,而ArticleController
处理直接从上下文中检索的对象。这让我觉得我应该重构这些控制器方法之一,以便更新所采取的步骤是相同的。我只是不确定我应该如何处理,因为这两种方法似乎应该能够对我共存。所以我的问题是,我可以改变什么来让两种类型的更新都能正常工作?
感谢您的宝贵时间,对于发布的大量代码,我感到非常抱歉。我只是觉得这一切都与问题有关。