8分钟学会使用AutoMapper

一.什么是AutoMapper与为什么用它。

它是一种对象与对象之间的映射器,让AutoMapper有意思的就是在于它提供了一些将类型A映射到类型B这种无聊的实例,只要B遵循AutoMapper已经建立的惯例,那么大多数情况下就可以进行相互映射了。

二.如何使用?

直接nuget install-package automapper 简单到不能再简单了。

三.入门

定义了连个简单的Model:

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<Destination, Source>());
            
Source source = AutoMapper.Mapper.Map<Source>(des);
            
Console.WriteLine(source.InfoUrl);
        
}

  Initialize方法是Mapper的初始化,里面可以写上CreateMap表达式,具体是谁和谁进行匹配。在之后就可以直接进行一个获取值的过程了,非常的简单。

四.映射前后操作

偶尔有的时候你可能需要在映射的过程中,你需要执行一些逻辑,这是非常常见的事情,所以AutoMapper给我们提供了BeforeMap和AfterMap两个函数。

1
2
3
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,你呢就可以用这两个对象去获取里面的值,说白了这就是循环去找里面的值了。

 五.条件映射

1
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配置

初始化配置是非常受欢迎的,每个领域都应该配置一次。

1
2
3
4
5
//初始化配置文件
Mapper.Initialize(cfg =>
{
    
cfg.CreateMap<Aliens, Person>();
});

 但是像这种情况呢,如果是多个映射,那么我们只能用Profile来配置,组织你的映射配置,并将配置放置到构造函数中(这种情况是5.x以上的版本),一个是以下的版本,已经被淘汰了。

5.0及以上版本:

1
2
3
4
5
6
7
public 
class 
AliensPersonProfile : Profile
    
{
        
public 
AliensPersonProfile()
        
{
            
CreateMap<Destination, Source>();
        
}
    
}

5.0以下版本(在早期版本中,使用配置方法而不是构造函数。 从版本5开始,Configure()已经过时。 它将在6.0中被删除。)

1
2
3
4
5
6
7
public 
class 
OrganizationProfile : Profile
{
    
protected 
override 
void 
Configure()
    
{
        
CreateMap<Foo, FooDto>();
    
}
}

 然后在程序启动的时候初始化即可。

1
Mapper.Initialize(x=>x.AddProfile<AliensPersonProfile>());

七.AutoMapper的最佳实践

上文中已经说到了AutoMapper的简单映射,但是在实际项目中,我们应该有很多类进行映射,这么多的映射应该怎么组织,这是一个活生生的问题,这成为主映射器。

在主映射器中,组织了多个小映射器,Configuration为我们的静态配置入口类;Profiles文件夹为我们所有Profile类的文件夹。如果是MVC,我们需要在Global中调用,那我的这个是控制台的。

1
2
3
4
5
6
7
8
public 
static 
void 
Configure()
        
{
            
Mapper.Initialize(cfg =>
            
{
                
cfg.AddProfile<DestinationSourceProfile>();
                
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<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方法通过依赖注入,开始映射过程,下图是代码和图。

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<CalendarEventForm>(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
/// <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);
        
}
    
}
}