愛上MVC3系(xi)列~使(shi)用(yong)視圖(tu)模型的(de)好(hao)處及與(yu)數據模型之間(jian)的(de)賦值(zhi)問題
MVC開(kai)發(fa)應用程序有個問(wen)題,很多(duo)開(kai)發(fa)者不(bu)知如何去使用頁(ye)面模型(xing),大(da)多(duo)數開(kai)發(fa)者認為(wei)為(wei)每(mei)一個頁(ye)面去設計一個實體是(shi)多(duo)余的,所以他們(men)使用數據庫實體來代碼(ma)頁(ye)面視圖模型(xing),事實上,這樣做的好處就(jiu)是(shi)節省的代碼(ma),但不(bu)好的地方是(shi)什(shen)么呢?我來總結一下吧:
1 方便根據每一種業(ye)務邏輯和(he)前臺頁面表現,去對模型進行特性的設置
2 前(qian)(qian)臺UI部分與(yu)業務層與(yu)數據庫(ku)層可以更加獨立,前(qian)(qian)臺頁面模型并(bing)不依賴于數據庫(ku)模型
3 可(ke)以根據(ju)具體業(ye)務,去分別設置它們的驗證及約(yue)束關系
好(hao)了,上面我說了3點不使用viewModel的(de)缺點,事實(shi)上,確實(shi)是(shi)這樣的(de),比(bi)如(ru),你的(de)userbase實(shi)體,如(ru)果(guo)它需要(yao)提供兩種業務,如(ru)“登陸”和“注冊”,那么它的(de)前(qian)臺信(xin)息展現與(yu)驗證業務肯(ken)定是(shi)不相同的(de),這時,如(ru)果(guo)使用ViewModel就很容易的(de)解(jie)決了這個問(wen)題。
以下(xia)是(shi)用戶模(mo)型的代(dai)碼(ma)片斷
1 /// <summary> 2 /// 用(yong)戶(hu)登陸視(shi)圖模(mo)型(xing) 3 /// </summary> 4 public class UserBaseLogOnModel 5 { 6 [Required] 7 [Display(Name = "用戶名(ming)")] 8 public string Name { get; set; } 9 [Required] 10 [DataType(DataType.Password)] 11 [Display(Name = "密碼(ma)")] 12 public string Password { get; set; } 13 [Required] 14 [Display(Name = "真(zhen)實(shi)姓名")] 15 public string RealName { get; set; } 16 } 17 /// <summary> 18 /// 用戶注(zhu)冊模(mo)型 19 /// </summary> 20 public class UserBaseRegisterModel 21 { 22 [Required] 23 [Display(Name = "用戶(hu)名")] 24 public string Name { get; set; } 25 [Required] 26 [DataType(DataType.Password)] 27 [Display(Name = "密(mi)碼")] 28 public string Password { get; set; } 29 [Required] 30 [DataType(DataType.Password)] 31 [Display(Name = "密碼")] 32 [Compare("Password", ErrorMessage = "新密碼(ma)和確認密碼(ma)不匹配。")] 33 public string ConfirmPassword { get; set; } 34 [Required] 35 [Display(Name = "真(zhen)實姓名")] 36 public string RealName { get; set; } 37 [Required] 38 [DataType(DataType.EmailAddress)] 39 [Display(Name = "電子郵件")] 40 public string Email { get; set; } 41 [Required] 42 [DataType(DataType.PhoneNumber)] 43 [Display(Name = "電話(hua)")] 44 public string Tel { get; set; } 45 [Required] 46 [Display(Name = "證(zheng)件類型(xing)")] 47 public SelectList IDType { get; set; } 48 [Required] 49 [Display(Name = "證件號碼(ma)")] 50 public string IDNumber { get; set; } 51 }
有了視圖(tu)模型,那(nei)我(wo)們(men)如何去使用(yong)它呢,我(wo)們(men)以用(yong)戶(hu)登陸為例(li),來(lai)說(shuo)一下吧:
首先,我們定義的(de)ViewModel里的(de)屬(shu)性(xing),要求和數據模(mo)型中(zhong)的(de)屬(shu)性(xing)名稱相同,這樣方便進(jin)行模(mo)型之(zhi)間的(de)賦值(zhi),用(yong)戶登陸與(yu)(yu)用(yong)戶注冊都是與(yu)(yu)userbase表相關的(de),
所(suo)以,在HTTPPost指(zhi)向(xiang)的(de)方(fang)法時,參數可以就是UserBase類型(xing)的(de),看代碼:
1 [HttpPost] 2 public ActionResult LogOn(UserBases entity) 3 { 4 }
而如(ru)果它(ta)們的屬(shu)性名稱是相(xiang)同(tong)的,MVC表單(dan)在(zai)進(jin)行POST請(qing)求(qiu)時,可以把屬(shu)性信(xin)息自動填充到參數實例上去,但如(ru)果你(ni)的模型(xing)中包括了導航屬(shu)性(其它(ta)關系表的實例),則(ze)需要手動為它(ta)進(jin)行初始(shi)化,如(ru)代碼:
1 [HttpPost] 2 public ActionResult LogOn(UserBases entity) 3 { 4 entity.User_Extensions_Extend = new User_Extensions(); 5 TryUpdateModel(entity.User_Extensions_Extend);//填充模型 6 }
當(dang)我(wo)們(men)從表單中(zhong)把數(shu)據得到后,要做(zuo)的(de)是什么呢?“驗證”,我(wo)們(men)需要知(zhi)道表單中(zhong)填寫(xie)的(de)內(nei)容是否是符合我(wo)們(men)設(she)定的(de)規范,如果(guo)不符合,則返回(hui)錯誤信息。
1 [HttpPost] 2 public ActionResult LogOn(UserBases entity) 3 { 4 entity.User_Extensions_Extend = new User_Extensions(); 5 TryUpdateModel(entity.User_Extensions_Extend);//填(tian)充模(mo)型(xing) 6 if (ModelState.IsValid) 7 { 8 VM = iUserRepository.Login(entity); 9 if (VM.IsComplete) 10 return RedirectToAction("Index", "Home"); 11 else 12 VM.ToList().ForEach(i => ModelState.AddModelError("", i)); 13 14 } 15 return View(); 16 }
在代碼(ma)中,我(wo)們并沒(mei)有(you)出(chu)現頁面中需要的(de)視力模型,它(ta)是(shi)如(ru)何與實體(ti)模型轉換的(de)呢,事(shi)實上,它(ta)們之間(jian)并沒(mei)有(you)發(fa)生(sheng)轉換,只是(shi)表單與實體(ti)之間(jian)發(fa)生(sheng)了(le)賦值而以,即
只要(yao)實體模型與視圖模型的屬性名相同,就完成可(ke)以使用MVC的自動賦值功能(TryUpdateModel)。