[Package] 利用AutoMapper轉換資料於DomainModel及ViewModel之間

利用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類別大同小異(可能少了幾個不需要的屬性以及屬性標籤內容不同)。

 

image

 

擾人的資料轉移

 

我們來分析一下資料處理的流程

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工具將這繁瑣的工作簡化。

image

 

將資料轉換的工作透過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 處理類別之間的對映轉換

AutoMapper 的設定 (Configuration)

 

 

參考資料

 

http://alantsai2007.blogspot.com/2014/09/BuildYourOwnApplicationFrameworkOnMvc-06-ViewModelIntro.html

http://alantsai2007.blogspot.com/2014/09/ithome-07-automapper-entityviewmodel.html


希望此篇文章可以幫助到需要的人

若內容有誤或有其他建議請不吝留言給筆者喔 !