Asp.net mvc 3 ViewModel删除并发异常不工作

Asp.net mvc 3 ViewModel删除并发异常不工作,asp.net-mvc-3,concurrency,viewmodel,Asp.net Mvc 3,Concurrency,Viewmodel,我正在努力捕捉并发异常。当用户编辑数据时,我能够捕获并发异常。当用户删除数据时,我很难捕获异常 在我的索引页面上,我有一个按钮来删除每个车辆对象。按下该按钮可执行删除操作。以下是删除操作: [HttpPost, ActionName("Delete")] public ActionResult DeleteConfirmed(VehicleIndexViewModel vehicleIndexViewModel) { try { Vehicle vehicle = db.Vehi

我正在努力捕捉并发异常。当用户编辑数据时,我能够捕获并发异常。当用户删除数据时,我很难捕获异常

在我的索引页面上,我有一个按钮来删除每个车辆对象。按下该按钮可执行删除操作。以下是删除操作:

[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(VehicleIndexViewModel vehicleIndexViewModel)
{
  try
  {
    Vehicle vehicle = db.Vehicles.Find(vehicleIndexViewModel.VehicleID);
    //To test for concurrency errors
    //vehicle.Timestamp = vehicleIndexViewModel.Timestamp;  

    db.Entry(vehicle).State = EntityState.Deleted;
    db.SaveChanges();
    return RedirectToAction("Index");
  }
  catch (DbUpdateConcurrencyException)
  {
    return RedirectToAction("Index", 
      new System.Web.Routing.RouteValueDictionary{{"concurrencyError", true }});
  }
  catch (DataException)
  {
    //Log the error (add a variable name after Exception)
    ModelState.AddModelError(string.Empty, "The system was unable to delete that" 
      + " vehicle. Try again, and if the problem persists"
      + " contact your system administrator.");
    return RedirectToAction("Index");
  }
}
不管怎样,用户都应该被重定向到索引页面。以下是索引页的获取操作:

公共视图结果索引(bool?concurrencyError)
{
if(concurrencyError.GetValueOrDefault())
{
ViewBag.concurrenceyerrormessage=“您试图删除的记录”
+“在您获得原始值后被另一用户修改。”
+“删除操作已取消,当前值在”
+“已显示数据库。如果仍要删除此”
+记录,再次单击“删除”按钮。否则
+“单击“返回列表”超链接。”;
}
IEnumerable vehicles=db.vehicles.包括(v=>v.VehicleType);
IEnumerable视图模型
=地图绘制者地图(车辆);
返回视图(viewModel);
}
代码永远不会捕获并发错误。我通过打开索引页两次进行测试。在其中一个页面上,我打开车辆的编辑页面并更改了一些内容。保存后,我返回到另一个页面并单击“删除”。删除操作启动,车辆被删除,但并发错误未被捕获。您可以看到我注释掉vehicle.Timestamp=vehicleIndexViewModel.Timestamp;的地方;。我认为将viewModel的值放回实际值会引起错误,但它也不能这样工作

我肯定有些事情我不明白,但我做错了什么


编辑


Erik Philips发现了我的逻辑错误,但我马上遇到了另一个问题。我的ViewModel没有返回时间戳数据。事实上,它返回的唯一数据是VehicleID

当我试图向表单添加隐藏字段时,我会得到一个错误。下面的代码不起作用:

<input type="hidden" name="Timestamp" value="@item"/>

时间戳字段必须是有效的Base-64字符串。您将得到的错误是:

输入不是有效的Base-64字符串,因为它包含非Base-64字符、两个以上的填充字符或填充字符中的非空白字符

这就是我如何在视图上存储时间戳值的原因:

<input type="hidden" name="Timestamp" value="@Convert.ToBase64String(item.Timestamp)"/> 

因此,我的整个Html.BeginForm如下所示:

@using (Html.BeginForm("Delete", "Vehicle",  FormMethod.Post, null))
{                                        
    <input type="hidden" name="VehicleID" value="@item.VehicleID"/>  
    <input type="hidden" name="VehicleName" value="@item.VehicleName"/> 
    <input type="hidden" name="Timestamp" value="@Convert.ToBase64String(item.Timestamp)"/>                                
    <input type="image" src="../../Content/Images/Delete.gif" value="Delete" name="deletevehicle @item.VehicleID" onclick="return confirm('Are you sure you want to delete @item.VehicleName.Replace("'", "").Replace("\"", "")?');"/>  
}  
@使用(Html.BeginForm(“删除”,“车辆”,FormMethod.Post,null))
{                                        

以下是我看到的情况,如果这些事件按此顺序发生:

用户1

车辆/编辑车辆ID=1(时间戳=1)

用户2

车辆/编辑车辆ID=1(时间戳=1)

用户1

车辆/更新车辆ID=1,Title=“一些文本”(时间戳=2)

User2

车辆/删除确认的车辆ID=1,时间戳=1

基本上,您所做的就是检索处于当前状态的车辆(从用户1更新)并将其删除。除非有人在
Find
SaveChanges
之间进行了更新,否则将永远不会出现
DbUpdateConcurrencyException


我认为您可以改为对上下文进行修改,删除它,然后调用
SaveChanges()

但在这种情况下,允许某人快速双击,从而导致两次潜在加载和重复删除。谢谢!这是我遇到的多个问题的开始。我将在下面发布其余问题的答案。
@using (Html.BeginForm("Delete", "Vehicle",  FormMethod.Post, null))
{                                        
    <input type="hidden" name="VehicleID" value="@item.VehicleID"/>  
    <input type="hidden" name="VehicleName" value="@item.VehicleName"/> 
    <input type="hidden" name="Timestamp" value="@Convert.ToBase64String(item.Timestamp)"/>                                
    <input type="image" src="../../Content/Images/Delete.gif" value="Delete" name="deletevehicle @item.VehicleID" onclick="return confirm('Are you sure you want to delete @item.VehicleName.Replace("'", "").Replace("\"", "")?');"/>  
}  
try
{
    Vehicle vehicle = Mapper.Map<VehicleIndexViewModel, Vehicle>(vehicleIndexViewModel);
    db.Entry(vehicle).State = EntityState.Deleted;
    db.SaveChanges();
    return RedirectToAction("Index");
}
catch (DbUpdateConcurrencyException)
{
    return RedirectToAction("Index", new System.Web.Routing.RouteValueDictionary { { "concurrencyError", true } });
}
/* DeleteConfirmed */

// Default Model Binder 
VehicleIndexViewModel.VehicleID = 1
VehicleIndexViewModel.Timestamp = 1

Vehicle vehicle = db.Vehicles.Find(vehicleIndexViewModel.VehicleID);
//vehicle.VehicleID = 1
//vehicle.Timestamp = 2

// Set to Delete
db.Entry(vehicle).State = EntityState.Deleted;

// Delete in database
db.SaveChanges();