简体   繁体   English

MVC3:存储库更新和ObjectStateManager

[英]MVC3: Repository Updates and ObjectStateManager

I have an Update method in my repository which I'm using to update articles on my project. 我的存储库中有一个Update方法,用于更新项目中的文章。 I was initially using this method only to carry out admin edits for articles. 最初,我只是使用这种方法来对文章进行管理员编辑。 It handles that correctly, but I decided I'd like to add a simple mechanism to calculate "most read" articles. 它可以正确处理,但是我决定添加一种简单的机制来计算“阅读次数最多”的文章。 In order to do that, I'd like to update TimesRead property each time an article has been viewed. 为了做到这一点,我想在每次查看文章时更新TimesRead属性。 This has been giving me trouble with the updates which seem to revolve around using ObjectStateManager.ChangeObjectState . 这给我带来了麻烦,似乎无法使用ObjectStateManager.ChangeObjectState进行更新。 Here's my Update method: 这是我的Update方法:

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

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

In my AdminController the following method updates correctly: 在我的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);
}

However, in the TimesRead scenario, the update will trigger an exception of: 但是,在TimesRead方案中,更新将触发以下异常:

The object cannot be attached because it is already in the object context. 无法附加对象,因为它已经在对象上下文中。 An object can only be reattached when it is in an unchanged state. 仅当对象处于未更改状态时才能重新附加对象。

Relevant code from that controller method: 该控制器方法中的相关代码:

var model = articleRepository.GetByID(id);

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

return View(model);

After having a look around to see what I can do to solve this, I came across the answer to this SO question. 在环顾四周以了解如何解决此问题后,我遇到了这个 SO问题的答案。 So I implemented that answer by replacing my Update method with the code suggested. 因此,我通过使用建议的代码替换Update方法来实现该答案。 This also works correctly in my admin scenario but not in the TimesRead scenario. 这在我的管理方案中也可以正常工作,但在TimesRead方案中则TimesRead The following exception is thrown: 引发以下异常:

An object with the same key already exists in the ObjectStateManager. 具有相同键的对象已存在于ObjectStateManager中。 The ObjectStateManager cannot track multiple objects with the same key. ObjectStateManager无法使用相同的键跟踪多个对象。

The exceptions are quite clear in their meaning but it does leave me wondering how I am supposed to handle simple updates such as these. 异常的含义非常清楚,但确实让我想知道如何处理此类简单更新。 I found that I can "fool" the EF into thinking the model is unchanged by setting EntityState.Unchanged and that will update TimesRead but give an exception for admin updates, stating the ObjectStateManager doesn't hold a reference to the object. 我发现我可以通过设置EntityState.Unchanged来“愚弄” EF,使其认为模型未更改,这将更新TimesRead但为管理员更新提供了一个例外,指出ObjectStateManager不保存对该对象的引用。

It's also clear to me how these scenarios differ. 我也很清楚这些情况有何不同。 The Edit action is mapping properties from a ViewModel onto a new, unattached Article object, whereas, ArticleController is dealing with an object retrieved directly from the context. Edit操作将属性从ViewModel映射到新的未附加的Article对象,而ArticleController处理直接从上下文检索的对象。 That leaves me with the feeling I should refactor one of those controller methods so the steps taken to update are the same. 这让我有一种感觉,我应该重构那些控制器方法中的一种,以便进行更新的步骤是相同的​​。 I'm just not really sure how I should even approach that as both approaches seem like they should be able to coexist to me. 我只是不太确定该如何处理,因为这两种方法似乎都应该能够与我共存。 So my question is, what can I change to get both types of update to work correctly? 所以我的问题是,我该如何更改才能使两种类型的更新正常工作?

Thanks for your time and I'm really sorry for the amount of code posted. 感谢您的宝贵时间,对于所发布的大量代码,我感到非常抱歉。 I just feel it is all relevant to the problem. 我只是觉得这与问题有关。

The primary difference between your two methods is that the Admin Edit method creates a new Article from your AdminEditViewModel, then it attaches this newly created Article to your database. 两种方法之间的主要区别是Admin Edit方法从AdminEditViewModel创建一个新的Article,然后将这个新创建的Article附加到您的数据库中。 This works because it's a new object that has never been attached to a dc. 之所以有效,是因为它是从未连接到dc的新对象。

In the second case, you get an Article from the repository, update that Article, then try and attach it again, this fails because it's not a newly created Article, it's an Article returned from the db Context in the first place so it's already attached. 在第二种情况下,您从存储库中获取了一条Article,对该Article进行了更新,然后尝试再次附加它,这失败了,因为它不是新创建的Article,它是从db Context返回的Article,因此它已经附加了。 and you are trying to attach it again. 您正在尝试再次附加它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM