ViewModel删除并发异常不起作用



我正在捕捉并发异常。当用户对数据进行精细编辑时,我能够捕捉到并发异常。当用户删除数据时,我很难捕捉到异常。

在我的索引页面上,我有一个删除每个车辆对象的按钮。按下该按钮将发布到删除操作。以下是删除操作:

[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");
  }
}

不管怎样,用户都应该重定向到索引页面。以下是索引页面的获取操作:

public ViewResult Index(bool? concurrencyError)
{
  if (concurrencyError.GetValueOrDefault())
  {
    ViewBag.ConcurrencyErrorMessage = "The record you attempted to delete "
      + "was modified by another user after you got the original values. "
      + "The delete operation was canceled and the current values in the "
      + "database have been displayed. If you still want to delete this "
      + "record, click the Delete button again. Otherwise "
      + "click the Back to List hyperlink.";
  }
  IEnumerable<Vehicle> vehicles = db.Vehicles.Include(v => v.VehicleType);
  IEnumerable<VehicleIndexViewModel> viewModel 
    = Mapper.Map<IEnumerable<Vehicle>, 
                 IEnumerable<VehicleIndexViewModel>>(vehicles);
  return View(viewModel);
}

代码永远不会捕捉到并发错误。我通过打开索引页两次进行测试。在其中一个页面上,我打开一辆车的编辑页面,更改了一些内容。保存后,我返回另一个页面并单击"删除"。删除操作启动,车辆被删除,但并发错误没有被捕获 你可以看到我在哪里评论车辆。时间戳=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(""", "")?');"/>  
}  

尽管如此,我真的不需要把VehicleName放在一个隐藏的字段中。

完成后,我所需要做的就是使用AutoMapper将值映射回车辆对象,将EntityState设置为Deleted,并尝试SaveChanges;

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 } });
}

就是这样!

如果这些事件按以下顺序发生,我会看到什么:

用户1

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

用户2

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

用户1

车辆/更新车辆ID=1,标题="某些文本",(时间戳=2)

用户2

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

/* 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();

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

我相信您可以做的是将对象附加到上下文,删除它,然后调用SaveChanges()

相关内容

  • 没有找到相关文章

最新更新