一. 什么是 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);
- }
- }
- }
来源: https://www.cnblogs.com/ZaraNet/p/10000311.html