上節說到了AutoMapper的簡單使用,對於復雜的Mapping需要強大的自定義,這節我們來看下AutoMapper的自定義Mapping(Projection)
搬運自Git:https://github.com/AutoMapper/AutoMapper/wiki/Projection
本篇的場景是一個簡單的日歷事件,我們首先定義一個日歷的事件如下:
1 public class CalendarEvent 2 { 3 //事件日期 4 public DateTime Date { get; set; } 5 //事件標題 6 public string Title { get; set; } 7 }
那麼在頁面,我們需要顯示這個事件的具體信息,而且是可編輯的,定義一個ViewModel dto如下:
1 public class CalendarEventForm 2 { 3 //事件日期 4 public DateTime EventDate { get; set; } 5 //時間對應的小時 6 public int EventHour { get; set; } 7 //時間對應的分鐘 8 public int EventMinute { get; set; } 9 //事件標題 10 public string Title { get; set; } 11 }
也許你會小小的糾結下,為啥要這麼定義,頁面上js直接轉換之類的,好吧,這就是一個例子,你明白就好。
接下來和本系列一貫的做法一樣,我們來看下手寫Mapping的方式:
1 // 定義一個日歷事件 2 var calendarEvent = new CalendarEvent 3 { 4 Date = new DateTime(2014, 12, 15, 20, 30, 0), 5 Title = "公司聚會" 6 }; 7 8 CalendarEventForm form = new CalendarEventForm 9 { 10 EventDate = calendarEvent.Date.Date, 11 EventHour = calendarEvent.Date.Hour, 12 EventMinute = calendarEvent.Date.Minute, 13 Title = calendarEvent.Title 14 };
這個Mapping依然很簡單,沒什麼疑問,咱們來對比下使用AutoMapper:
1 // 配置Mapping 2 Mapper.CreateMap<CalendarEvent, CalendarEventForm>() 3 .ForMember(dest => dest.EventDate, opt => opt.MapFrom(src => src.Date.Date)) 4 .ForMember(dest => dest.EventHour, opt => opt.MapFrom(src => src.Date.Hour)) 5 .ForMember(dest => dest.EventMinute, opt => opt.MapFrom(src => src.Date.Minute)); 6 7 //Mapping 8 CalendarEventForm form = Mapper.Map<CalendarEvent, CalendarEventForm>(calendarEvent);
有什麼感想?是不是感覺代碼高大上,但是跟手寫的沒啥區別,哈哈,別著急,這只是一個例子。對於復雜的場景,你自然會體會到AutoMapper使代碼簡潔,配置統一。
說道配置這裡需要說明一下:Mapping的配置並不是這樣每次都要Create的,具體的說明,請期待下篇 《AutoMapper之配置》
回到上面的代碼,我們來進一步的說明下這個ForMember
AutoMapper提供了相關的API來支持自定義的Mapping配置,並且他支持lamda哦。
看一下ForMember的定義:
1 IMappingExpression<TSource, TDestination> ForMember(Expression<Func<TDestination, object>> destinationMember
第一個參數是目標屬性,第二個參數是一定義的映射Expression, Expression讓這個映射變得更加的動態,可以直接使用表達式或者干脆直接來個函數調用:
1 .ForMember(dest => dest.Title, opt => opt.MapFrom(src => ChangeTitle(src.Title));//調用方法 2 .ForMember(dest => dest.Title, opt => opt.MapForm(src => src.Title.Where(....);//表達式 3 4 string ChangeTitle(string title) 5 { 6 //自定義處理 7 ... 8 9 return "myName" + title; 10 }
有關Expression的內容及構造請參考表達式的文章,這裡邊的水很深,有機會我也去深入研究分享些內容。
細心的你或許會發現,如果映射寫了多個會怎麼樣?經過測試,結論是:只有第一個配置是有效的,之後的同參數映射AutoMapper會自動忽略。
另外,還有一個ForMembers函數不過並不是很常用,其他的函數請自行研究,如果我有研究使用後面的系列我會一一分享。本節仍然是簡單的內容,如果大家有更好的建議請留言,我覺得可能搬運的太簡單,沒有給人具體的映象的感覺。
AutoMapper?舉個最簡單的例子。
比如在ORM中,與數據庫交互用的Model模型是具有很多屬性變量方法神馬的。而當我們與其它系統(或系統中的其它結構)進行數據交互時,出於耦合性考慮或者安全性考慮或者性能考慮(總之就是各種考慮),我們不希望直接將這個Model模型傳遞給它們,這時我們會創建一個貧血模型來保存數據並傳遞。神馬是貧血模型?貧血模型(DTO,Data Transfer Object)就是說只包含屬性神馬的,只能保存必須的數據,木有其它任何的多余的方法數據什麼的,專門用於數據傳遞用的類型對象。在這個創建的過程中,如果我們手動來進行,就會看到這樣的代碼:
B b=new B();
b.XXX1=a.XXX1;
b.XXX2=a.XXX2;
...
...
...
return b;
此時,AutoMapper可以發揮的作用就是根據A的模型和B的模型中的定義,自動將A模型映射為一個全新的B模型。從而避免寫這樣又臭又長又無聊的代碼。SO,理解為代碼生成器也可以……