1. 程式人生 > >[ASP.net教程]物件對映工具AutoMapper介紹

[ASP.net教程]物件對映工具AutoMapper介紹

AutoMapper是用來解決物件之間對映轉換的類庫。對於我們開發人員來說,寫物件之間互相轉換的程式碼是一件極其浪費生命的事情,AutoMapper能夠幫助我們節省不少時間。

一. AutoMapper解決了什麼問題?

要問AutoMapper解決了什麼問題? 難道不是物件對映轉換的問題嗎? 
當然是,不過我們可以問深入一些,為什麼專案中會出現大量的物件對映轉換?(以下對於非MVC專案也適用)

在現代的軟體開發中,專案的層級更加的細分,而不同層級之間對於物件的需求是有區別的,這就需要在不同層級間傳遞資料的時候,必須要轉換資料。

舉一些實際具體的例子:
在持久層(資料訪問層), 我們的User物件,可能是一個包含User表中所有欄位的資料的物件,甚至包含了使用者的Password資訊。而在介面層,我們只是需要顯示使用者的name, email,不需要Password這些額外的資訊,同時,它還需要使用者的考勤資訊,而這個資訊來自於另外一張表。 
這個例子中,能夠發現不同層之間,我們對於資料物件的需求是不同的。 
每個層都做了它們職責範圍內的事情:

 
持久層關注資料,所以只提供資料物件,它無需知道外層如何使用這些資料物件,也無法知道。 
介面層關注資料的呈現,它只關注它要顯示的資料。

那麼問題是,誰來彌補它們之間的鴻溝?DTO(Data Transfer Object)——資料傳輸物件。而AutoMapper就是解決其中涉及到的資料物件轉換的工具。

clip_image001

在實際開發中,如果你還可以直接在Business層或者介面層直接使用持久層的物件,因為你認為這個關係不大,整個專案都是你自己控制的,雖然dirty,但是quick. 作為一個有些潔癖的程式設計師,我還是建議使用DTO在不同層級之間傳遞資料。因為當你做更高層級開發的時候,比如開發web service,WCF,Web API這些為系統外部提供介面的開發時候,你就回明白這些好的習慣和思維能夠幫助你更加好的設計這些外部介面。

二. AutoMapper如何使用?

先來看一個簡單的例子,這個例子是定義Order物件到OrderDto物件之間的對映。(我們把Order稱呼為源類,OrderDto稱呼為目標類)

Mapper.CreateMap<Order, OrderDto>();//建立對映關係Order –> OrderDtoOrderDto dto = Mapper.Map<OrderDto>(order);//使用Map方法,直接將order物件裝換成OrderDto物件

智慧匹配

AutoMapper能夠自動識別和匹配大部分物件屬性:

  • 如果源類和目標類的屬性名稱相同,直接匹配
  • 目標型別的CustomerName可以匹配源型別的Customer.Name
  • 目標型別的Total可以匹配源型別的GetTotal()方法

自定義匹配規則

AutoMapper還支援自定義匹配規則

Mapper.CreateMap<CalendarEvent, CalendarEventForm>()            //屬性匹配,匹配源類中WorkEvent.Date到EventDate            .ForMember(dest => dest.EventDate, opt => opt.MapFrom(src => src.WorkEvent.Date))            .ForMember(dest => dest.SomeValue, opt => opt.Ignore())//忽略目標類中的屬性            .ForMember(dest => dest.TotalAmount, opt => opt.MapFrom(src => src.TotalAmount ?? 0))//複雜的匹配            .ForMember(dest => dest.OrderDate, opt => opt.UserValue<DateTime>(DateTime.Now));固定值匹配

測試
當定義完規則後,可以使用下面的程式碼來驗證配置是否正確。不正確丟擲異常AutoMapperConfigurationException.

Mapper.AssertConfigurationIsValid();

三. AutoMapper處理多對一對映

我們開篇提到的問題中,說到介面顯示User的name, email, 還有使用者的考勤資訊,而這些資訊來自於2張不同的表。這就涉及到了多對一對映的問題,2個持久層物件需要對映到一個介面顯示層的物件。

假設我們的持久層物件是這樣的:

public class User{    public int Id { get; set; }    public string Name { get; set; }    public string Email { get; set; }    public string Passworkd { get; set; }    public DateTime Birthday { get; set; }}public class Evaluation{    public int Id { get; set; }    public int Score { get; set; }}

在Asp.net MVC中,我的介面顯示層的ViewModel是這樣的

public class UserViewModel{    public int Id { get; set; }    public string Name { get; set; }    public string Email { get; set; }    public int Score { get; set; }}

接下來,為了達到多對一的對映的目的,我們建立這個EntityMapper類

public static class EntityMapper{    public static T Map<T>(params object[] sources) where T : class    {      if (!sources.Any())      {        return default(T);      }      var initialSource = sources[0];      var mappingResult = Map<T>(initialSource);      // Now map the remaining source objects      if (sources.Count() > 1)      {        Map(mappingResult, sources.Skip(1).ToArray());      }      return mappingResult;    }    private static void Map(object destination, params object[] sources)    {      if (!sources.Any())      {        return;      }      var destinationType = destination.GetType();      foreach (var source in sources)      {        var sourceType = source.GetType();        Mapper.Map(source, destination, sourceType, destinationType);      }    }    private static T Map<T>(object source) where T : class    {      var destinationType = typeof(T);      var sourceType = source.GetType();      var mappingResult = Mapper.Map(source, sourceType, destinationType);      return mappingResult as T;    }  }

為了實現多個源物件對映一個目標物件,我們使用了AutoMapper的方法,從不同的源物件逐一匹配一個已經存在的目標物件。下面是實際使用在MVC中的程式碼:

public ActionResult Index(){     var userId = 23,     var user = _userRepository.Get(userId);     var score = _scoreRepository.GetScore(userId);     var userViewModel = EntityMapper.Map<UserViewModel>(user, score);     return this.View(userViewModel);}

四. 使用Profile在Asp.net MVC專案中配置AutoMapper

ProfileAutoMapper中用來分離型別對映定義的,這樣可以讓我們的定義AutoMapper型別匹配的程式碼可以更加分散,合理和易於管理。

利用Profile, 我們可以更加優雅的在MVC專案中使用我們的AutoMapper. 下面是具體的方法:

1.  在不同層中定義Profile,只定義本層中的型別對映

繼承AutoMapping的Profile類,重寫ProfileName屬性和Configure()方法。

public class ViewModelMappingProfile: Profile{    public override string ProfileName    {      get      {        return GetType().Name;      }    }    protected override void Configure()    {      Mapper.CreateMap......    }}

2. 建立AutoMapperConfiguration, 提供靜態方法Configure,一次載入所有層中Profile定義

public class AutoMapperConfiguration{    public static void Configure()    {      Mapper.Initialize(x => x.AddProfile<ViewModelMappingProfile>());      Mapper.AssertConfigurationIsValid();    }}

3. 在Global.cs檔案中執行

最後,在Global.cs檔案中程式啟動前,呼叫該方法

AutoMapperConfiguration.Configuration()

轉載原文地址:http://www.shaoqun.com/a/99411.aspx