[英]MVC3: Repository Updates and ObjectStateManager
我的存储库中有一个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问题的答案。 因此,我通过使用建议的代码替换Update
方法来实现该答案。 这在我的管理方案中也可以正常工作,但在TimesRead
方案中则TimesRead
。 引发以下异常:
具有相同键的对象已存在于ObjectStateManager中。 ObjectStateManager无法使用相同的键跟踪多个对象。
异常的含义非常清楚,但确实让我想知道如何处理此类简单更新。 我发现我可以通过设置EntityState.Unchanged
来“愚弄” EF,使其认为模型未更改,这将更新TimesRead
但为管理员更新提供了一个例外,指出ObjectStateManager
不保存对该对象的引用。
我也很清楚这些情况有何不同。 Edit
操作将属性从ViewModel映射到新的未附加的Article
对象,而ArticleController
处理直接从上下文检索的对象。 这让我有一种感觉,我应该重构那些控制器方法中的一种,以便进行更新的步骤是相同的。 我只是不太确定该如何处理,因为这两种方法似乎都应该能够与我共存。 所以我的问题是,我该如何更改才能使两种类型的更新正常工作?
感谢您的宝贵时间,对于所发布的大量代码,我感到非常抱歉。 我只是觉得这与问题有关。
两种方法之间的主要区别是Admin Edit
方法从AdminEditViewModel创建一个新的Article,然后将这个新创建的Article附加到您的数据库中。 之所以有效,是因为它是从未连接到dc的新对象。
在第二种情况下,您从存储库中获取了一条Article,对该Article进行了更新,然后尝试再次附加它,这失败了,因为它不是新创建的Article,它是从db Context返回的Article,因此它已经附加了。 您正在尝试再次附加它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.