MVC3: Обновления репозитория и ObjectStateManager - PullRequest
0 голосов
/ 24 июля 2011

У меня есть метод 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 имеет дело с объектом, полученным непосредственно из контекста.Это оставляет у меня ощущение, что я должен рефакторинг одного из этих методов контроллера, чтобы шаги, предпринятые для обновления, были такими же.Я просто не совсем уверен, как я должен подходить к этому, поскольку оба подхода кажутся способными сосуществовать со мной.Итак, мой вопрос: что я могу изменить, чтобы оба типа обновлений работали правильно?

Спасибо за ваше время, и мне очень жаль за количество размещенного кода.Я просто чувствую, что все это имеет отношение к проблеме.

1 Ответ

0 голосов
/ 24 июля 2011

Основное различие между вашими двумя методами состоит в том, что метод Admin Edit создает новую Статью из вашей AdminEditViewModel, а затем присоединяет эту вновь созданную Статью к вашей базе данных.Это работает, потому что это новый объект, который никогда не был присоединен к постоянному току.

Во втором случае вы получаете Статью из репозитория, обновляете эту Статью, затем пытаетесь присоединить ее снова, это не удается, потому что этоэто не недавно созданная статья, это статья, возвращенная из контекста БД, поэтому она уже прикреплена.и вы пытаетесь прикрепить его снова.

...