一.什么是AutoMapper与为什么用它。
它是一种对象与对象之间的映射器,让AutoMapper有意思的就是在于它提供了一些将类型A映射到类型B这种无聊的实例,只要B遵循AutoMapper已经建立的惯例,那么大多数情况下就可以进行相互映射了。
二.如何使用?
直接nuget install-package automapper 简单到不能再简单了。
三.入门
定义了连个简单的Model:
+ View Code
1
2
3
4
5
6
7
8
9
10
11
static void Main(string[] args)
        {
            Destination des = new Destination()
            {
                InfoUrl = "www.cnblogs.com/zaranet",
                name ="张子浩"
            };
            Mapper.Initialize(x => x.CreateMap
());
            Source source = AutoMapper.Mapper.Map(des);
            Console.WriteLine(source.InfoUrl);
        }
  Initialize方法是Mapper的初始化,里面可以写上CreateMap表达式,具体是谁和谁进行匹配。在之后就可以直接进行一个获取值的过程了,非常的简单。
四.映射前后操作
偶尔有的时候你可能需要在映射的过程中,你需要执行一些逻辑,这是非常常见的事情,所以AutoMapper给我们提供了BeforeMap和AfterMap两个函数。
1
2
3
Mapper.Initialize(x => x.CreateMap().BeforeMap(
                (src,dest)=>src.InfoUrl ="https://"+src.InfoUrl).AfterMap(
                (src,dest)=>src.name="真棒"+src.name));
其中呢,src是Destination对象,dest是Source,你呢就可以用这两个对象去获取里面的值,说白了这就是循环去找里面的值了。
 五.条件映射
1
Mapper.Initialize(x => x.CreateMap().ForMember(dest => dest.InfoUrl,opt => opt.Condition(dest => dest.InfoUrl == "www.cnblogs.com/zaranet1")).ForMember(...(.ForMember(...))));
在条件映射中,通过ForMember函数,参数是一个委托类型Fun<>,其里面呢也是可以进行嵌套的,但一般来说一个就够用了。
六.AutoMapper配置
初始化配置是非常受欢迎的,每个领域都应该配置一次。
1
2
3
4
5
//初始化配置文件
Mapper.Initialize(cfg =>
{
    cfg.CreateMap();
});
 但是像这种情况呢,如果是多个映射,那么我们只能用Profile来配置,组织你的映射配置,并将配置放置到构造函数中(这种情况是5.x以上的版本),一个是以下的版本,已经被淘汰了。
5.0及以上版本:
1
2
3
4
5
6
7
public class AliensPersonProfile : Profile
    {
        public AliensPersonProfile()
        {
            CreateMap();
        }
    }
5.0以下版本(在早期版本中,使用配置方法而不是构造函数。 从版本5开始,Configure()已经过时。 它将在6.0中被删除。)
1
2
3
4
5
6
7
public class OrganizationProfile : Profile
{
    protected override void Configure()
    {
        CreateMap();
    }
}
 然后在程序启动的时候初始化即可。
1
Mapper.Initialize(x=>x.AddProfile());
七.AutoMapper的最佳实践
上文中已经说到了AutoMapper的简单映射,但是在实际项目中,我们应该有很多类进行映射,这么多的映射应该怎么组织,这是一个活生生的问题,这成为主映射器。
在主映射器中,组织了多个小映射器,Configuration为我们的静态配置入口类;Profiles文件夹为我们所有Profile类的文件夹。如果是MVC,我们需要在Global中调用,那我的这个是控制台的。
1
2
3
4
5
6
7
8
public static void Configure()
        {
            Mapper.Initialize(cfg =>
            {
                cfg.AddProfile();
                cfg.AddProfile(new StudentSourceProfile());
            });
        }
其中添加子映射,可以用以上两种方式。
1
2
3
4
public void Configuration(IAppBuilder app)
        {
            AutoMapperConfiguration.Configure();
        }
八.指定映射字段
在实际业务环境中,你不可能说两个类的字段是一 一 对应的,这个时候我们就要对应它们的映射关系。
1
2
3
4
5
6
7
8
9
10
11
12
13
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定义如下:
1
2
3
4
5
6
7
8
9
10
11
public class CalendarEventProfile : Profile
   {
       public CalendarEventProfile()
       {
           CreateMap()
          .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方法通过依赖注入,开始映射过程,下图是代码和图。
1
2
3
4
5
6
7
8
9
10
11
static void Main(string[] args)
        {
            CalendarEvent calendar = new CalendarEvent()
            {
                Date = DateTime.Now,
                Title = "Demo Event"
            };
            AutoMapperConfiguration.Configure();
            CalendarEventForm calendarEventForm = Mapper.Map(calendar);
            Console.WriteLine(calendarEventForm);
        }   
  
那么最后呢,如果是反向的映射,一定回缺少属性,那么就你就可以obj.属性进行赋值。
附AutoHelper封装类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/// 
    /// AutoMapper扩展帮助类
    /// 
    public static class AutoMapperHelper
    {
        /// 
        ///  类型映射
        /// 
        public static T MapTo(this object obj)
        {
            if (obj == null) return default(T);
            Mapper.CreateMap(obj.GetType(), typeof(T));
            return Mapper.Map(obj);
        }
        /// 
        /// 集合列表类型映射
        /// 
        public static List MapToList(this IEnumerable source)
        {
            foreach (var first in source)
            {
                var type = first.GetType();
                Mapper.CreateMap(type, typeof(TDestination));
                break;
            }
            return Mapper.Map>(source);
        }
        /// 
        /// 集合列表类型映射
        /// 
        public static List MapToList(this IEnumerable source)
        {
            //IEnumerable 类型需要创建元素的映射
            Mapper.CreateMap();
            return Mapper.Map>(source);
        }
        /// 
        /// 类型映射
        /// 
        public static TDestination MapTo(this TSource source, TDestination destination)
            where TSource : class
            where TDestination : class
        {
           if (source == null) return destination;
            Mapper.CreateMap();
            return Mapper.Map(source, destination);
        }
        /// 
        /// DataReader映射
        /// 
        public static IEnumerable DataReaderMapTo(this IDataReader reader)
        {
            Mapper.Reset();
            Mapper.CreateMap>();
            return Mapper.Map>(reader);
        }
    }
}https://www.cnblogs.com/ZaraNet/p/10000311.html