這幾天,工作上需要製作一個Data Grid型式的Edit Form做
CRUD,
技術上使用ASP.NET MVC4 / EntityFramework 5.0 / Scaffolding,因為一個小小低級錯誤,導致出現
DbUpdateConcurrencyException,了解這個錯誤後,在此講解一下,順道亦介紹一下相關的
OptimisticConcurrencyException。
DbUpdateConcurrencyException
這是EF 5.0新增的Exception,如圖所示,這通常會出現在
SaveChanges()的時候。
Exception Message :
中文 :
存放區更新、插入或刪除陳述式影響到非預期數目的資料列 (0)。這些實體載入之後可能被修改或刪除了。請重新整理 ObjectStateManager 實體。
英文 :
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
原因 :
就如Exception Message所說,這個錯誤會出現在INSERT / UPDATE / DELETE,原因是出現非預期的Affected Row數目。
那我們就要想一想什麼原因會導致Affected Row是 "0"。
1. 遺失Primary Key
以我工作上的例子,MVC4 Scaffolding建立的View都是
含@model keyword的strongly-typed view。
理論上你按Submit ,Post form後,ActionResult應該都會做
Model-Binding。
但有時候,因為一些人為錯誤,就會導致接收的Model數值不完整。
例如我這個情況,把DropDownList設定disabled,Post form後,那就沒有CompanyID了。出現"0"是因為CompanyID是int Type預設值而已。
那EF 跟本找不到符合的紀錄,固然亦UPDATE不能,所以就回報"0"Rows了。
這情況亦會出現在UPDATE和INSERT的場景上,所以要多加注意。
但有時我們真的需要把DropDownList / TextBox等等設定為Disabled,那怎麼辦?
那跟ASP.NET Webforms時一樣,加上一個HiddenField吧。
Razor 方法:
@Html.HiddenFor(model => model.CompanyID)
2. 同時Parallel作業
這就是所謂的並行處理(Concurrency)。
舉一個簡單的例子,Ken開啟了某客戶的Edit Form,想把電話修改一下,開啟後,Ken離開了崗位,但Edit Form依然開著。
幾分鐘後,Cammy把這位客戶的資料刪除。
當Ken 回到崗位後,修改了客戶的電話,按儲存。
就會出現
DbUpdateConcurrencyException了。
原因很明顯就是找不到紀錄。
OptimisticConcurrencyException
跟上面的同時Parallel作業很相似,但
OptimisticConcurrencyException只會發生在UPDATE的時候。
兩位使用者同時修改同一項目,Ken更新電話,Cammy更新地址,只要數值正確,雙方都可以進行儲存。
只是如果Ken和Cammy都是更新電話的話,就要Handle
OptimisticConcurrencyException這個Exception進行Resolve Conflicts。
可以看看下列兩條連結的做法,是不簡單的。
不過由此可以見到EF發展到5.0版本已經是一個功能強大,安全的Framework。
Handling Concurrency with the Entity Framework in an ASP.NET MVC Application
Handling Concurrency with the Entity Framework 4.0 in an ASP.NET Web Application