Параллелизм ASP.NET MVC с RowVersion в действии редактирования - PullRequest
2 голосов
/ 05 мая 2010

Я хочу сделать простую форму редактирования для нашего приложения отслеживания проблем. Для простоты действие HttpGet Edit выглядит примерно так:

    // Issues/Edit/12
    public ActionResult Edit(int id)
    {
        var thisIssue = edmx.Issues.First(i => i.IssueID == id);
        return View(thisIssue);
    }

, а затем действие HttpPost выглядит примерно так:

    [HttpPost]
    public ActionResult Edit(int id, FormCollection form)
    {
        // this is the dumb part where I grab the object before I update it.
        // concurrency is sidestepped here.
        var thisIssue = edmx.Issues.Single(c => c.IssueID == id);

        TryUpdateModel(thisIssue);
        if (ModelState.IsValid)
        {
            edmx.SaveChanges();

            TempData["message"] = string.Format("Issue #{0} successfully modified.", id);
            return RedirectToAction("Index");
        }

        return View(thisIssue);
    }

Который работает чудесно. Однако проверка параллелизма не работает, потому что в Посте я повторно получаю текущую сущность прямо перед тем, как пытаюсь обновить ее. Тем не менее, с EF я не знаю, как использовать причудливость SaveChanges(), но прикрепить мой thisIssue к контексту. Я пытался позвонить edmx.Issues.Attach(thisIssue), но я получил

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.

Как мне справиться с параллелизмом в MVC с EF и / или как правильно Attach отредактировать мой отредактированный объект в контексте?

Заранее спасибо

Ответы [ 2 ]

6 голосов
/ 05 мая 2010

То, что вы делаете, сложно, но можно заставить работать. Предположим, ваше поле метки времени называется ConcurrencyToken. Очевидно, что вы должны включить это значение в представление и отправить его вместе с формой. Но вы не можете просто присвоить это значение thisIssue.ConcurrencyToken в POST, потому что EF запомнит как «старое» значение (значение, которое вы извлекли из БД при вызове Single(), так и «новое» "значение (из вашей формы) и используйте" старое "значение в предложении WHERE. Поэтому вам нужно лгать EF и назначать правильное значение. Попробуйте это:

    var thisIssue = edmx.Issues.Single(c => c.IssueID == id);
    TryUpdateModel(thisIssue); // assign ConcurrencyToken
    var ose = Context.ObjectStateManager.GetObjectStateEntry(entityToUpdate);
    ose.AcceptChanges();       // pretend object is unchanged
    TryUpdateModel(thisIssue); // assign rest of properties

Вы можете оптимизировать это, связывая только ConcurrencyToken вместо двухкратного вызова TryUpdateModel, но это должно помочь вам начать.

5 голосов
/ 15 мая 2013

Ниже приведен пример выполнения обновлений, совместимых с оптимистическим параллелизмом, с использованием EF5 (метод происходит из репозитория.) Предполагается, что объект определяет метку времени с [ConcurrencyCheck]. Исключение параллелизма возникает при вызове DbContext.SaveChanges().

public TEntity Update(TEntity entity)
{
    var attached = this.GetById(entity.Id);
    if (attached == null)
    {
        throw new MvcBootstrapDataException("{0} with Id = {1} does not exist.".F(typeof(TEntity).Description(), entity.Id));
    }

    var entry = this.Context.Entry(attached);

    // The Timestamp must be in the original values for optimistic concurrency checking to occur.
    // Otherwise the context knows that the Timestamp has been modified in the context
    entry.OriginalValues["Timestamp"] = entity.Timestamp;

    entry.CurrentValues.SetValues(entity);

    attached.Modified = DateTime.Now;

    return attached;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...