ASP.NET MVC 使用TryUpdateModel 更新的技巧
- 有使用 ASP.NET MVC 的朋友應該會對於 TryUpdateModel 有一定的認知,他不但可以利用 Metadata 來做欄位的驗證確保資料的正確性,也可以指定更新的條件以及不更新的條件來達到萬用的功能,因為他的好用所以 demo 也是經常使用他,但是使用的時候多少會覺得每次都要指定欄位很麻煩嗎?這裡告訴大家一個小技巧,讓你的 TryUpdateModel 更順手。
TryUpdateModel 是擁有 10個多載的方法,所以可以應用範圍是很廣的,本文將利用 ActionFilter 的技巧來設定排除的欄位。
最簡單的寫法就是這樣寫
var oldData = _r.GetSingleData(id); if (TryUpdateModel(oldData,new string[]{"欄位一,欄位二"})) { _r.Save(); }
第一個參數為要被更新的資料,所以必須要先查出來,第二個參數就是指定要更新的欄位,但是因為每個資料表都不一樣每次都要寫很麻煩,因此你可以改成以下寫法
public ActionResult Edit(Guid id, FormCollection collection) { var oldData = _r.GetSingleData(id); if (TryUpdateModel(oldData, collection.AllKeys)) { _r.Save(); } }
這次利用了 FormCollection 來接 View 傳過來的 Key 來做要更新的資料,省去了每次都要自己 new 字串陣列的麻煩。
但是很多時候不一定頁面傳過來的都是我們要更新的欄位所以會進一步設定排除的欄位
public ActionResult Edit(Guid id, FormCollection collection) { var oldData = _r.GetSingleData(id); if (TryUpdateModel(oldData,"", collection.AllKeys,new string[]{"ID","Name"})) { _r.Save(); } }
如上方程式,排除了 ID 和 Name 欄位的更新
正常情況來說 每個人都有習慣開資料庫的習慣,比如說一定會有 建立時間和建立使用者,但這些東西不希望被更新雖然他已經是固定的可以寫死,但是我只能說上面的 Code 有點醜....所以我們來建立一個 ActionFilter 來玩玩。
建立一個名稱為ModelStateExcludeAttribute 的 ActionFilter,註解就寫在程式內
/// <summary> /// 預設排除ModelState的 ID、CreateUser、CreateTime欄位驗證 /// 並且使用ViewData[Exclude]回傳 /// </summary> public class ModelStateExcludeAttribute : ActionFilterAttribute { public string[] Exclude { get; set; } /// <summary> /// 預設排除ModelState的 ID、CreateUser、CreateTime欄位驗證 /// 並且使用ViewData[Exclude]回傳 /// </summary> public ModelStateExcludeAttribute() { Exclude = new string[] { "ID", "CreateTime", "CreateUser" }; } /// <summary> /// 可以自訂排除欄位,使用 , 分隔 /// 並且使用ViewData[Exclude]回傳 /// </summary> public ModelStateExcludeAttribute(string exclude) { if (exclude != null) { if (exclude.Contains(",")) Exclude = exclude.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); else Exclude = new string[] { exclude }; } } /// <summary> /// 進入 Action 的時候執行 /// </summary> /// <param name="filterContext"></param> public override void OnActionExecuting(ActionExecutingContext filterContext) { foreach (var item in Exclude) { //將排除欄位一一設定 filterContext.Controller.ViewData.ModelState.Remove(item); } //設定完畢後將他利用 ViewData 傳到 Action 內 filterContext.Controller.ViewData["Exclude"] = Exclude; } }
有了這個 ActionFilter 就可以回頭改一下 Controller 的程式了,調整如下
[ModelStateExclude] public ActionResult Edit(Guid id, FormCollection collection) { var oldData = _r.GetSingleData(id); if (TryUpdateModel(oldData,"", collection.AllKeys,ViewData["Exclude"] as string[])) { _r.Save(); } }
看的到增加了 ModelStateExclude 這個Attribute以及原本自行宣告字串陣列的排除欄位改用 ViewData 接了
預設的情況下就是排除掉預設的欄位,如果想自訂排除欄位就可以這樣寫
[ModelStateExclude("排除一,排除二")]
以上這種寫法好處在哪呢?
一來利用了 ActionFilter來定義那就可以一目了然,並且更利於單元測試的撰寫,而且你會發現整段更新的程式沒有扯到資料庫物件,因此如果你是產生器來產 Code 的,這種寫法更適合。