8分鐘學會使用AutoMapper
一.什麽是AutoMapper與為什麽用它。
它是一種對象與對象之間的映射器,讓AutoMapper有意思的就是在於它提供了一些將類型A映射到類型B這種無聊的實例,只要B遵循AutoMapper已經建立的慣例,那麽大多數情況下就可以進行相互映射了。
二.如何使用?
直接nuget install-package automapper 簡單到不能再簡單了。
三.入門
定義了連個簡單的Model:
public class Destination { public string name { get; set; } public string InfoUrl { get; set; } } public class Source { public string name { get; set; } public string InfoUrl { get; set; } public string aa { get; set; } }
static void Main(string[] args) { Destination des = new Destination() { InfoUrl = "www.cnblogs.com/zaranet", name ="張子浩" }; Mapper.Initialize(x => x.CreateMap<Destination, Source>()); Source source = AutoMapper.Mapper.Map<Source>(des); Console.WriteLine(source.InfoUrl); }
Initialize方法是Mapper的初始化,裏面可以寫上CreateMap表達式,具體是誰和誰進行匹配。在之後就可以直接進行一個獲取值的過程了,非常的簡單。
四.映射前後操作
偶爾有的時候你可能需要在映射的過程中,你需要執行一些邏輯,這是非常常見的事情,所以AutoMapper給我們提供了BeforeMap和AfterMap兩個函數。
Mapper.Initialize(x => x.CreateMap<Destination, Source>().BeforeMap( (src,dest)=>src.InfoUrl ="https://"+src.InfoUrl).AfterMap( (src,dest)=>src.name="真棒"+src.name));
其中呢,src是Destination對象,dest是Source,你呢就可以用這兩個對象去獲取裏面的值,說白了這就是循環去找裏面的值了。
五.條件映射
Mapper.Initialize(x => x.CreateMap<Destination, Source>().ForMember(dest => dest.InfoUrl,opt => opt.Condition(dest => dest.InfoUrl == "www.cnblogs.com/zaranet1")).ForMember(...(.ForMember(...))));
在條件映射中,通過ForMember函數,參數是一個委托類型Fun<>,其裏面呢也是可以進行嵌套的,但一般來說一個就夠用了。
六.AutoMapper配置
初始化配置是非常受歡迎的,每個領域都應該配置一次。
//初始化配置文件 Mapper.Initialize(cfg => { cfg.CreateMap<Aliens, Person>(); });
但是像這種情況呢,如果是多個映射,那麽我們只能用Profile來配置,組織你的映射配置,並將配置放置到構造函數中(這種情況是5.x以上的版本),一個是以下的版本,已經被淘汰了。
5.0及以上版本:
public class AliensPersonProfile : Profile { public AliensPersonProfile() { CreateMap<Destination, Source>(); } }
5.0以下版本(在早期版本中,使用配置方法而不是構造函數。 從版本5開始,Configure()
已經過時。 它將在6.0中被刪除。)
public class OrganizationProfile : Profile { protected override void Configure() { CreateMap<Foo, FooDto>(); } }
然後在程序啟動的時候初始化即可。
Mapper.Initialize(x=>x.AddProfile<AliensPersonProfile>());
七.AutoMapper的最佳實踐
上文中已經說到了AutoMapper的簡單映射,但是在實際項目中,我們應該有很多類進行映射,這麽多的映射應該怎麽組織,這是一個活生生的問題,這成為主映射器。
在主映射器中,組織了多個小映射器,Configuration為我們的靜態配置入口類;Profiles文件夾為我們所有Profile類的文件夾。如果是MVC,我們需要在Global中調用,那我的這個是控制臺的。
public static void Configure() { Mapper.Initialize(cfg => { cfg.AddProfile<DestinationSourceProfile>(); cfg.AddProfile(new StudentSourceProfile()); }); }
其中添加子映射,可以用以上兩種方式。
public void Configuration(IAppBuilder app) { AutoMapperConfiguration.Configure(); }
八.指定映射字段
在實際業務環境中,你不可能說兩個類的字段是一 一 對應的,這個時候我們就要對應它們的映射關系。
public class CalendarEvent { public DateTime Date { get; set; } public string Title { get; set; } } public class CalendarEventForm { public DateTime EventDate { get; set; } public int EventHour { get; set; } public int EventMinute { get; set; } public string DisplayTitle { get; set; } }
在這兩個類中,CalendarEvent的Date將被拆分為CalendarEventForm的日期、時、分三個字段,Title也將對應DisplayTitle字段,那麽相應的Profile定義如下:
public class CalendarEventProfile : Profile { public CalendarEventProfile() { 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)) .ForMember(dest => dest.DisplayTitle, opt => opt.MapFrom(src => src.Title)); } }
main方法通過依賴註入,開始映射過程,下圖是代碼和圖。
static void Main(string[] args) { CalendarEvent calendar = new CalendarEvent() { Date = DateTime.Now, Title = "Demo Event" }; AutoMapperConfiguration.Configure(); CalendarEventForm calendarEventForm = Mapper.Map<CalendarEventForm>(calendar); Console.WriteLine(calendarEventForm); }
那麽最後呢,如果是反向的映射,一定回缺少屬性,那麽就你就可以obj.屬性進行賦值。
附AutoHelper封裝類
/// <summary> /// AutoMapper擴展幫助類 /// </summary> public static class AutoMapperHelper { /// <summary> /// 類型映射 /// </summary> public static T MapTo<T>(this object obj) { if (obj == null) return default(T); Mapper.CreateMap(obj.GetType(), typeof(T)); return Mapper.Map<T>(obj); } /// <summary> /// 集合列表類型映射 /// </summary> public static List<TDestination> MapToList<TDestination>(this IEnumerable source) { foreach (var first in source) { var type = first.GetType(); Mapper.CreateMap(type, typeof(TDestination)); break; } return Mapper.Map<List<TDestination>>(source); } /// <summary> /// 集合列表類型映射 /// </summary> public static List<TDestination> MapToList<TSource, TDestination>(this IEnumerable<TSource> source) { //IEnumerable<T> 類型需要創建元素的映射 Mapper.CreateMap<TSource, TDestination>(); return Mapper.Map<List<TDestination>>(source); } /// <summary> /// 類型映射 /// </summary> public static TDestination MapTo<TSource, TDestination>(this TSource source, TDestination destination) where TSource : class where TDestination : class { if (source == null) return destination; Mapper.CreateMap<TSource, TDestination>(); return Mapper.Map(source, destination); } /// <summary> /// DataReader映射 /// </summary> public static IEnumerable<T> DataReaderMapTo<T>(this IDataReader reader) { Mapper.Reset(); Mapper.CreateMap<IDataReader, IEnumerable<T>>(); return Mapper.Map<IDataReader, IEnumerable<T>>(reader); } } }
8分鐘學會使用AutoMapper