閱讀目錄
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
坐車回家過年了,祝大家新年愉快。
作者:蘑菇先生
出處: http://mushroom.cnblogs.com/
本文版權歸作者和部落格園共有,歡迎轉載。未經作者同意下,必須在文章頁面明顯标出原文連結及作者,否則保留追究法律責任的權利。
如果您認為這篇文章還不錯或者有所收獲,可以點選右下角的
【推薦】按鈕,因為你的支援是我繼續寫作,分享的最大動力!