У меня есть метод 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);
После осмотра, чтобы увидеть, что я могу сделатьчтобы решить это, я наткнулся на ответ на этот ТАК вопрос.Поэтому я реализовал этот ответ, заменив мой метод Update
предложенным кодом.Это также работает правильно в моем сценарии администратора, но не в сценарии TimesRead
.Выдается следующее исключение:
Объект с таким же ключом уже существует в ObjectStateManager.ObjectStateManager не может отслеживать несколько объектов с одним и тем же ключом.
Исключения достаточно ясны по своему значению, но это заставляет меня задуматься о том, как я должен обрабатывать простые обновления, подобные этим.Я обнаружил, что могу «обмануть» EF, думая, что модель неизменна, установив EntityState.Unchanged
, и это обновит TimesRead
, но даст исключение для обновлений администратора, заявив, что ObjectStateManager
не содержит ссылку на объект.
Мне также ясно, как эти сценарии отличаются.Действие Edit
отображает свойства из ViewModel на новый неприкрепленный объект Article
, тогда как ArticleController
имеет дело с объектом, полученным непосредственно из контекста.Это оставляет у меня ощущение, что я должен рефакторинг одного из этих методов контроллера, чтобы шаги, предпринятые для обновления, были такими же.Я просто не совсем уверен, как я должен подходить к этому, поскольку оба подхода кажутся способными сосуществовать со мной.Итак, мой вопрос: что я могу изменить, чтобы оба типа обновлений работали правильно?
Спасибо за ваше время, и мне очень жаль за количество размещенного кода.Я просто чувствую, что все это имеет отношение к проблеме.