AutoMapper使用手冊(一)

蘑菇先生發表於2015-02-14

閱讀目錄

  1. 介紹

  2. 基本使用

  3. 自動分割對映(Flattening)

  4. 自定義欄位對映(Projection)

  5. 驗證配置(Configuration validation)

介紹

AutoMapper是一個輕量級的類庫,主要功能是把一個物件轉換成另外一個物件,而避免我們每次都手工去轉換。

常見幾種使用場景:

  • 對外服務介面,把邏輯層的實體轉換成服務消費者需要的欄位。

  • UI展現層,把業務物件轉換成UI需要展現的欄位。

  • 使用者的輸入輸出,把DTO與領域模型互轉。

AutoMapper支援的平臺:

  • .NET 4+
  • Silverlight 5
  • Windows Phone 8+
  • .NET for Windows Store apps (WinRT)
  • Windows Universal Apps
  • Xamarin.iOS
  • Xamarin.Android

基本使用

NuGet安裝使用

PM> install-package automapper

註冊2個型別之間的對映關係:

Mapper.CreateMap<Order, OrderDto>();

通過Map方法生成目標型別新物件,OrderDto是目標型別,order是源物件。

OrderDto dto = Mapper.Map<OrderDto>(order);

AutoMapper預設是根據屬性名稱自動與源進行規則匹配,賦值。
例:FirstName=FirstName,FirstName=firstname,mapper不區分大小寫。

配置

使用靜態全域性mapper註冊的話,應該放在應用程式啟動的時候。
比如ASP.NET的Global.asax檔案中Application_Start()方法。

測試

AutoMapper提供下面方法去驗證我們的配置是否有效,無效會丟擲異常:

Mapper.AssertConfigurationIsValid();

自動分割對映(Flattening)

實際中我們經常需要把一個複雜物件對映一個簡單物件,給UI使用,例:

public class Order
{
    public Customer Customer { get; set; }
    public decimal GetTotal()
    {
        return 10*10;
    }
}
 public class Customer
    {
        public string Name { get; set; }
    }

然後匹配Order物件到一個簡單的OrderDto,僅包含我們需要的欄位:

public class OrderDto
{
    public string CustomerName { get; set; }
    public decimal Total { get; set; }
}

當我們使用AutoMapper建立Order/OrderDto對映配置時,AutoMapper對映器會嘗試在Order中,尋找名稱匹配的成員,有3種匹配方式。

  • 名稱相同的屬性進行對映,不區分大小寫。
  • 帶Get字首的方法進行對映,如例子中:
    對映器會把Order中的GetTotal分割成Get、Total 2個詞, 把分割出來的Total與OrderDto中的Order進行匹配對映。
  • 目標型別屬性分割,如例子中: 對映器會把OrderDto中的CustomerName分割成Customer、Name。然後在Order中去Customer類屬性中查詢Name的屬性。

內部匹配根據帕斯卡拼寫法(PascalCase)。

自定義欄位對映(Projection)

自動分割對映能預判源物件到目標物件的匹配,但不能自定義配置對映。AutoMapper在構造目標物件時,會自動按照規則進行目標與源屬性分割匹配。
所以自動分割對映雖然方便智慧,但卻不是那麼精確可控制的。 在很多場景下,我們更需要的是把A屬性拆分對映B、C 2個屬性上,或單獨對映D屬性上。
AutoMapper提供一種自定義成員對映的方法。例如:

public class CalendarEvent
{
    public DateTime Date { get; set; }
    public string Title { get; set; }
}

我們想在web頁面上輸出更多的欄位:

public class CalendarEventForm
{
    public DateTime EventDate { get; set; }
    public int EventHour { get; set; }
    public int EventMinute { get; set; }
    public string Title { get; set; }
}

因為目標型別的屬性不存在源上,所以AutoMapper也無法完成精確匹配。 我們需要自定義成員對映規則到我們的型別對映配置上面。

// 源物件
var calendarEvent = new CalendarEvent
    {
        Date = new DateTime(2008, 12, 15, 20, 30, 0),
        Title = "假期公司聚會"
    };

// 配置AutoMapper。   dest是目標表示式。opt是源表示式
Mapper.CreateMap<CalendarEvent, CalendarEventForm>()
    .ForMember(dest => dest.EventDate, opt => opt.MapFrom(src => src.Date.Date))
    .ForMember(dest => dest.EventHour, opt => opt.MapFrom(src => src.Date.Hour))
    .ForMember(dest => dest.EventMinute, opt => opt.MapFrom(src => src.Date.Minute));

// 執行對映
CalendarEventForm form = Mapper.Map<CalendarEvent, CalendarEventForm>(calendarEvent);

form.EventDate.ShouldEqual(new DateTime(2008, 12, 15));
form.EventHour.ShouldEqual(20);
form.EventMinute.ShouldEqual(30);
form.Title.ShouldEqual("假期公司聚會");

ForMember方法允許我們指定2個action委託去配置每個成員的對映關係。 在上面的例子中,我們在源表示式使用了MapFrom方法去執行源值與目標成員的對映。這個MapFrom方法接受一個lambda表示式為引數,它在物件對映期間進行求值,即惰性求值。MapFrom引數可以是任意一個func的lambda表示式。

驗證配置(Configuration validation)

平常我們手工進行物件對映,雖然很枯燥無味,但有利於我們測試轉換。在這個源型別到目標型別轉換基礎測試上,其實我們仍然需要測試自己的應用。 AutoMapper也想到了這點,它減少的不僅僅是我們手工進行物件對映的事情,還能幫助我們節省手工寫測試程式碼的時間。

AutoMapper提供了AssertConfigurationIsValid方法去測試我們的配置項。 假設我們有個輕微的錯誤在源型別和目標型別上: 

public class Source 
{
public int SomeValue { get; set; }
}
public class Destination
{
    public int SomeValuefff { get; set; }
}

在Destination上,我們可能不小心輸入錯誤,多了幾個fff。也可能是我們的源屬性重新命名了。

我們去測試配置項,建立對映配置並且執行AssertConfigurationIsValid方法。

Mapper.CreateMap<Source, Destination>();
Mapper.AssertConfigurationIsValid();

在程式碼執行期間會丟擲一個AutoMapperConfigurationException異常,描述訊息為:

 Unmapped members were found. Review the types and members below.
 Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type
  ==============================================================
Source -> Destination (Destination member list)
ConsoleApplication1.Source -> ConsoleApplication1.Destination (Destination member list)
Unmapped properties:
SomeValuefff

AssertConfigurationIsValid執行驗證期間,AutoMapper會檢查每個目標型別的屬性,逐一去匹配源中是否存在合適相等的型別。

異常處理(Overriding configuration errors)

除了我們去修改源和目標型別的名稱外。 我們有3種選擇去解決錯誤:

  • 自定義值解析器
  • 指定欄位對映(Projection)
  • 使用忽略(Ignore())選項

關於第三種選擇,在目標型別我們有個成員,它有其他的含義(非字面意思或預留欄位), 我們不想進行轉換,我們可以配置如下:

 Mapper.CreateMap<Source, Destination>()
    .ForMember(dest => dest.SomeValuefff, opt => opt.Ignore());

官方文件:https://github.com/AutoMapper/AutoMapper 

 

坐車回家過年了,祝大家新年愉快。

相關文章