2012-04-03 20 views
0

我正致力於捕獲併發異常。我能夠在用戶編輯好數據時捕獲併發異常。我在用戶刪除數據時遇到了異常。ViewModel刪除併發Excecption不起作用

在我的索引頁面上,我有一個按鈕來刪除每個車輛對象。按下該按鈕將執行Delete(刪除)操作Post。這裏是刪除操作:

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

的代碼永遠不會捕捉併發性錯誤。我通過兩次打開索引頁來測試。在其中一頁上,我打開車輛的編輯頁面並改變一些內容。保存完成後,我會回到其他頁面並點擊「刪除」。 刪除操作被觸發,車輛被刪除,但併發錯誤未被捕獲。你可以看到我在哪裏註釋vehicle.Timestamp = vehicleIndexViewModel.Timestamp ;.我認爲將viewModel的值放回到實際中會引起錯誤,但它也不會以這種方式工作。

我敢肯定,這只是我不明白的,但是我做錯了什麼?


編輯


埃裏克飛利浦發現,我有邏輯錯誤,但是,我遇到了馬上另一個問題。我的ViewModel沒有返回Timestamp數據。事實上,它返回的唯一數據是VehicleID。

當我試圖向表單添加一個隱藏字段時,會出現錯誤。下面的代碼將不起作用:

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

時間戳字段需要是有效的Base-64字符串。你將得到的錯誤是:

輸入不是一個有效的Base-64字符串,因爲它包含非基本填充中最多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

這是我所看到的,如果這些事件發生的順序會發生:

用戶1

車輛/編輯VehicleID = 1(時間戳= 1)

用戶2

車輛/編輯VehicleID = 1(時間戳= 1)

用戶1

車輛/更新VehicleID = 1,標題= 「一些文本」,(時間戳= 2)

用戶2

車輛/ DeleteConfirmed VehicleID = 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

我相信你可以做的事情就是將Attach the object放到上下文中,刪除它,然後撥打SaveChanges()

+0

但在這種情況下,它允許有人快速雙擊,因此兩個潛在負載和重複刪除。 – 2012-04-03 02:27:15

+0

謝謝!這是我遇到的多個問題的開始。我將在下面回答其餘問題。 – user1304444 2012-04-03 03:08:25