利用AutoMapper轉換資料於DomainModel及ViewModel之間
前言
在使用Asp.Net MVC開發系統時,我們通常會先建立Domain Model,並透過Entity Framework將這些Domain Model對應到實體的DB Table中且建立相對Schema來(Code First)。一般而言架構師會將這些Domain Model封裝在Domain.dll函式庫中供各層使用,也會另建立資料存取層(或服務層)透過DbContext來取出我們希望的資料來呈現於畫面中。
如上文所述,我們再換個角度從前端來思考,當一個Http Request進入後透過Routing的機制來到某個Controller的Action後,若是要新增一筆資料時,我們往往會直接將DomainModel中Entity直接作為MVC Model Binding物件使用,並且透過Entity上的屬性標籤Attribute(ex. Required, MaxLength, DisplayName)作為View資料檢核或呈現屬性名稱之依據;試想個情況,當我們有2個頁面都使用到相同Domain Model,但所需的檢核不同、屬性顯示名稱也不同情況下該如何處理呢?
比較多人的做法會針對各個View來建立相對應的ViewModel來做為資料的載體。如處理帳號新增的UserController之Create Action所使用的ViewModel就會命名為UserCreateViewModel,而此ViewModel類別將會具有所希望乘載的各屬性物件列於其中,例如新增帳號一定需要UserModel類別,但其實在ViewModel中的UserModel與Domain Model中的User類別大同小異(可能少了幾個不需要的屬性以及屬性標籤內容不同)。
擾人的資料轉移
我們來分析一下資料處理的流程
1. 用戶 Post Data 進入Controller的Action
2. 透過MVC將資料綁定至ViewModel的UserModel屬性物件中
3. 建立DomainModel的User類別物件實體
4. 將 ViewModel的UserModel資料 轉移至 DomainModel的User中
5. 呼叫資料存取層(或服務層)將DomainModel的User資料寫入DB中
擾人的問題就發生在第4點過程中。由於這個轉換過程是相當繁瑣且無意義的事情,目的就只是把兩個相似的類別資料進行傳遞而已,如下片段程式所示。
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(UserCreateViewModel viewModel)
{
if (ModelState.IsValid)
{
// Transfer data from ViewModel to DomainModel
User user = new User();
user.Name = viewModel.UserModel.Name;
user.Password = viewModel.UserModel.Password;
user.UserId = viewModel.UserModel.UserId;
user.Email = viewModel.UserModel.Email;
user.IsEnable = viewModel.UserModel.IsEnable;
user.RegisterOn = System.DateTime.Now; /* default */
// save to db
_uow.UserService.AddUser(user);
_uow.Save();
return RedirectToAction("Index");
}
return View(viewModel);
}
解決方案
我們可以透過AutoMapper工具將這繁瑣的工作簡化。
將資料轉換的工作透過AutoMapper的幫忙進行簡化,如下所示:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(UserCreateViewModel viewModel)
{
if (ModelState.IsValid)
{
// Transfer data from ViewModel to DomainModel
Mapper.CreateMap<UserCreateViewModel.UserModel, User>()
.ForMember(u=>u.RegisterOn, opt=>opt.MapFrom(x=>DateTime.Now));
var user = Mapper.Map<User>(viewModel.UserModel);
// save to db
_uow.UserService.AddUser(user);
_uow.Save();
return RedirectToAction("Index");
}
return View(viewModel);
}
在此筆者只簡單的應證其功效,如果有興趣的讀者可以參考以下資訊有更進一步轉換細節說明
AutoMapper 的設定 (Configuration)
參考資料
http://alantsai2007.blogspot.com/2014/09/ithome-07-automapper-entityviewmodel.html
希望此篇文章可以幫助到需要的人
若內容有誤或有其他建議請不吝留言給筆者喔 !