先前我們已經用 Scaffolding 建立簡易的 CRUD 功能,不過可以發現,像是 Create 時,理應不需要填寫 CreateUser
, CreateTime
, UpdateUser
, UpdateTime
的欄位,這時候我們該怎麼辦才好呢? ViewModel 就可以派上用場了
ViewModel 就像是針對不同的 View 所建立的 Model,它可以用來與 Controller 及 View 之間傳值,並且是強型別的方式,避免使用 ViewData、ViewBag 弱型別會導致型別錯誤的問題發生。
且 ViewModel 也能協助我們將兩個不同 Model 結合起來,e.g. Events 和 EventsInfo,這在後續會實際撰寫到。
在前言提到,CreateUser
, CreateTime
, UpdateUser
, UpdateTime
的欄位我們是不需要自行填寫的,且 UpdateUser
, UpdateTime
更是不會在新增頁面就儲存這兩個欄位的值到 DB,所以我們在 ViewModel 中就不會放 UpdateUser
, UpdateTime
。
另外有個 CategoryId
的欄位,先前我們有設計了一個 EventsCategory 的 Model 與 Table,不過現在我們先為了方便測試,就先使用 enum 的類別來建立下拉選單與傳值給 CategoryId
。
其實就只要把原本的 Model 複製過來,大部分就完成了,只是可以看到我多新增了 EventsCategoryEnum
這一個 Field。
在 View 的第一行開始通常會是指定這一個 View 要接收哪一個 Model,在原本 Events 的 Create.cshtml,Model 是指定為 Events
,此時我們要更改為 EventsCreateViewModel
。
另外也可以看到參考了 EventsSystem_iThome.Enum
,因為下拉選單會參考 EventsCategoryEnum
類別,並使用 Tag Helper 做出下拉選單。
Model 指定為 EventsCreateViewModel
後,可以發現 UpdateUser
, UpdateTime
的部分會發生錯誤,這是因為 EventsCreateViewModel
內沒有這兩個欄位,所以無法指定。
而我將 CategoryId
的 Code 也移除了,替換的是 Enum 的取值:
Scaffold 的 Controller,在 Model Binding 預設是產生弱型別的 Binding(Create()的參數),這樣的方法其實是不好的,且如果欄位增減,參數也需手動更新。
ASP.NET Core 提供了 Model Binding 的功能,Action 的參數只要指定好(e.g. 型別指定為 Model;或是 int Id,參數名設定跟 PK 一樣),那麼在 View 傳值到後端時,ASP.NET Core 會自動幫你將傳過來的值綁定在參數。
不過要傳到 DbContext 並新增資料至 DB 時,DbContext 接收的是原本的 Events
Model 類別,EventsCreateViewModel
是無法直接放在 DbContext 的,此時需要將 ViewModel 的值都丟還給 Model。
可以 new Events
並將 EventsCreateViewModel
的 field 都一個一個指派到 Events
,但這樣實在太慢了,此時有一個非常棒的套件可以來協助我們,AutoMapper。
使用 Nuget 安裝 AutoMapper。
AutoMapper 讓我們可以用幾行的 Code 就做到 ViewModel 與 Model 間的欄位傳值,首先建立一個對應的型別定義 MapperConfiguration
,在 <> 的左方為來源型別,右方則為目的型別,左方會放置 ViewModel,右方則是 Model。
接著實體化對應器 mapperConfig.CreateMapper();
,實體化後使用 Map()
並先指定目的型別(Events 這一個 Model),並將 EventsCreateViewModel
放在參數中,如此就完成了 ViewModel 與 Model 間的對應,現在 Model 的 Field 已經都存好值了。
此時將對應完的 events
放到 DbContext,就可以執行新增的 Function 了!
ViewModel 提供了更輕量化且更有彈性的 View 的傳值中介,ViewModel 與 View 一樣,它不該放置任何邏輯與其他方法,越單純越好。
AutoMapper 為 Model 間的對應減少了非常多的 Code,不需要寫很多個 A = B
就可以完成對應,我認為是一個在使用 ASP.NET Core 開發程式時,必須要安裝的套件。
[鐵人賽Day11] ASP.Net Core MVC 進化之路 - View(1) / 資料傳遞及Razor語法
ASP.NET MVC 的 ViewModel - 基礎篇
列舉類型 (c # 參考)
Get Int Value From Enum in C#