AutoMapper的神奇魔法

  • 564
  • 0
  • 2016-07-11

AutoMapper不但可以讓程式碼變乾淨,出錯的機會變少,還能達到關注點分離的效果唷

前言

在設計MVC網站時,常會對view特別客製化一個viewModel,可是在設計repository時,為了講求共用性,不可能每個view都為他設計專屬的repository取資料,所以repository回傳的型別通常都會以資料表的layout為主。

但這樣一來,就會發現一個問題,當我們要把repository回傳的物件轉換成viewModel時,常需要寫很多轉換的程式碼,不僅麻煩又會讓程式看起來髒髒的。因此,如能定義一次對應的規則,之後就直接一行程式碼搞定這種對應的關係,將會十分的便利。

 

建立環境

現在已經有很多方便的套件可以幫我們達到這個效果,這邊使用的是autoMapper的套件。

假設我們有已經有有一個Member和MemberViewModel的類別

想要建立這兩個類別的轉換只要做三個步驟

  1. 撰寫轉換類別的Profile
  2. 建立Configuration,將Profile注入
  3. 使用Configuration建立mapper

之後便可使用建立的mapper在程式碼中任意轉換兩個類別,而無需撰寫對應的邏輯

 

範例程式

首先,建立要轉換的類別關聯的Profile

    public class MemberViewModelMappingProfile:Profile
    {
        protected override void Configure()
        {
            this.CreateMap<Member, MemberViewModel>();
        }
    }

建立Profile有三個重點,第一要繼承Profile,Profile是來自AutoMapper的命名空間,第二要override他的Configure方法,最後則是建立要轉換的類別即可,這裡是用泛型的方式來實作,第一個是要轉換的型別,第二個是轉換後的型別。三個步驟完成後,它就很智慧的做到同屬性如果型別相同就會自動做轉換。

下一個步驟則是建立Configuration,這裡的寫法很固定,一般來講這裡會用DI的方式注入,但這邊為了減少複雜性,就直接寫在程式裡而沒有特別拉一個專門處理注入的專案出來。

 var profile = new MemberViewModelMappingProfile();

 var config = new MapperConfiguration(
                  cfg =>
                  {
                     cfg.AddProfile(profile);
                  });

最後利用這個configuration就可以建立mapper,拿到mapper之後就可以任意對有註冊過Profile的類別來做轉換了。

var mapper = config.CreateMapper();

利用mapper要轉換一個類別就相當容易,沒有複雜的程式碼,只需要短短一行就可以做到,呼叫Map方法,泛型的部分是要轉換的目標類別,接受的參數是轉換前的物件,然後就完成了。

 var member= new Member();
 var memberViewModel = mapper.Map<MemberViewModel>(member);

 

複雜轉換

前面的範例程式,只適用於比較簡單的類別轉換,只要屬性名稱一樣,AutoMapper就會常是幫助你轉換程目標類別,但假如物件裡的屬性不僅僅只有基本型別呢,其實那也不難,直接看看例子就好了。

轉換前的類別

   public class Member
    {
        public Guid Id { get; set; }

        public Account account { get; set; }
    }

    public class Account
    {
        public string account { get; set; }
        
        public string password { get; set; }
    }

想要轉換的目標類別

 public class MemberViewModel
    {
        public Guid Id { get; set; }

        public AccountViewModel account { get; set; }
    }

    public class AccountViewModel
    {
        public string account { get; set; }

        public string password { get; set; }
    }

如果只單純照原本的範例程式寫,會出現下列錯誤

其實它只是在說,它不知道Account這個類別要怎麼對應,因為它只會幫你自動對應基礎型別,那要怎麼做呢?其實仔細思考就會知道,再複雜的類別不也是基礎類別組成的嗎?所以,如果把Account也當作基礎型別幫它建立mapper不就一切搞定了?那就直接來實作吧,只需要在原本的Profile加一行就可以解決了。

    public class MemberViewModelMappingProfile:Profile
    {
        protected override void Configure()
        {
            this.CreateMap<Member, MemberViewModel>();
            this.CreateMap<Account, AccpntViewModel>();
        }
    }

簡單來講,再複雜的型別,只要掌握一個原則,只要不是基本型別的屬性,都幫它建立map,這樣不管類別再複雜都能化繁為簡。

額外附帶一提,如果Account屬性是IEnumerable<Account>的集合型別要怎改?答案是完全不用改,AutoMapper非常聰明,它會自動根據我們Create的Mapper來對這個集合做對應。

 

結論

AutoMapper可以達到關注點分離的效果,讓我們的商業邏輯層可以不被類別轉換的程式碼干擾,尤其是當類別屬性非常複雜時少轉換一個屬性,而造成不可預期的錯誤,這種bug常常一下子就吃掉程式設計師不少的時間。AutoMapper就可以幫助我們處理這些瑣事,不但能讓程式碼變乾淨,發生錯誤的機會也相對變少很多。