2010-05-05 79 views
2

我想为我们的问题跟踪应用程序做一个简单的编辑表单。为简单起见,HTTPGET编辑动作看起来是这样的:ASP.NET MVC并发与RowVersion编辑操作

// 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. 

我该如何处理并发的MVC与EF和/或如何正确Attach我编辑的对象的背景?

在此先感谢

回答

6

你在做什么是棘手的,但可以使工作。假设您的时间戳字段被称为ConcurrencyToken。显然,你必须在视图中包含这个值,并将其与表单一起提交。但是,您不能简单地将其分配给POST中的值thisIssue.ConcurrencyToken,因为EF将记住“旧”值(您从DB调用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而不是调用优化这个两次,但这应该让你开始。

+0

好吧,那肯定会起作用,但它肯定会感觉不舒服。没有办法只是说这是我的问题对象;将此问题对象附加到问题#12,并使用这里存储的值更新问题#12?这样,它把它放在数据库上,以确保#12问题仍然有相同的时间戳... 此外,你可以进一步详细说明我只怎么绑定ConcurrencyToken字段? – Jorin 2010-05-05 19:46:37

+0

您只通过传递白名单来绑定一个字段;这有一个过载。要做你想要更新的内容,你需要创建一个存根对象,将它附加到上下文中,并更新它。这可以防止从数据库中获取更新的'ConcurrencyToken'。 – 2010-05-05 19:52:28

+0

对不起,我确定我只是很密集,但你能否拼出一些关于如何将某些东西剔除并附加的东西。我想这和它没有工作 \t \t [HttpPost] \t \t公众的ActionResult编辑(INT ID,发行号) \t \t { \t \t \t问题newIssue =新问题(); \t \t \t newIssue.IssueID = id; \t \t \t newIssue。EntityKey = new System.Data.EntityKey(“MayflyEntities.Issues”,“IssueID”,id); \t \t \t edmx.Issues.Attach(newIssue); \t \t \t newIssue = issue; \t \t \t edmx.SaveChanges(); \t \t} – Jorin 2010-05-05 20:21:17

4

一个使用EF5执行乐观并发兼容更新的示例如下(该方法来自reposi )假定实体用[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; 
}