AutoMapper不但可以讓程式碼變乾淨,出錯的機會變少,還能達到關注點分離的效果唷
前言
在設計MVC網站時,常會對view特別客製化一個viewModel,可是在設計repository時,為了講求共用性,不可能每個view都為他設計專屬的repository取資料,所以repository回傳的型別通常都會以資料表的layout為主。
但這樣一來,就會發現一個問題,當我們要把repository回傳的物件轉換成viewModel時,常需要寫很多轉換的程式碼,不僅麻煩又會讓程式看起來髒髒的。因此,如能定義一次對應的規則,之後就直接一行程式碼搞定這種對應的關係,將會十分的便利。
建立環境
現在已經有很多方便的套件可以幫我們達到這個效果,這邊使用的是autoMapper的套件。
假設我們有已經有有一個Member和MemberViewModel的類別
想要建立這兩個類別的轉換只要做三個步驟
- 撰寫轉換類別的Profile
- 建立Configuration,將Profile注入
- 使用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就可以幫助我們處理這些瑣事,不但能讓程式碼變乾淨,發生錯誤的機會也相對變少很多。