一.什么是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);
}
}
}
