繁体   English   中英

编辑操作中使用RowVersion的ASP.NET MVC并发

[英]ASP.NET MVC Concurrency with RowVersion in Edit Action

我想为我们的问题跟踪应用程序做一个简单的编辑表单。 为简单起见,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);
    }

这非常有效。 但是,并发检查不起作用,因为在Post中,我正在尝试更新它之前重新检索当前实体。 但是,使用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.

如何使用EF处理MVC中的并发和/或如何Attach我编辑的对象正确Attach到上下文?

提前致谢

你在做什么是棘手的,但可以使其工作。 让我们假设你的timestamp字段叫做ConcurrencyToken 显然,您必须在视图中包含此值并将其与表单一起提交。 但是你不能简单地将它分配给POST中thisIssue.ConcurrencyToken的值,因为EF将记住“旧”值(你通过调用Single()从DB获取的值以及“new” “value(来自您的表单)并使用WHERE子句中的”old“值。因此您需要骗取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来优化此操作,但这应该可以帮助您入门。

下面是使用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;
}

暂无
暂无

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

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