初识AutoMapper
在开始本篇文章之前,先来思考一个问题:一个项目分多层架构,如显示层、业务逻辑层、服务层、数据访问层。层与层访问需要数据载体,也就是类。如果多层通用一个类,一则会暴露出每层的字段,二者会使类字段很多,而且会出现很多冗余字段,这种方式是不可取的;如果每层都使用不同的类,则层与层调用时,一个字段一个字段的赋值又会很麻烦。针对第二种情况,可以使用AutoMapper来帮助我们实现类字段的赋值及转换。
AutoMapper是一个对象映射器,它可以将一个一种类型的对象转换为另一种类型的对象。AutoMapper提供了映射规则及操作方法,使我们不用过多配置就可以映射两个类。
安装AutoMapper
通过Nuget安装AutoMapper,本次使用版本为6.2.2。
AutoMapper配置
初始化
先创建两个类用于映射:
1
2
3
4
5
6
7
8
9
10
11
|
public
class
ProductEntity
{
public
string
Name {
get
;
set
; }
public
decimal
Amount {
get
;
set
; }
}
public
class
ProductDTO
{
public
string
Name {
get
;
set
; }
public
decimal
Amount {
get
;
set
; }
}
|
Automapper可以使用静态类和实例方法来创建映射,下面分别使用这两种方式来实现 ProductEntity -> ProductDTO的映射。
- 使用静态方式
1
2
|
Mapper.Initialize(cfg => cfg.CreateMap<ProductEntity, ProductDTO>());
var
productDTO = Mapper.Map<ProductDTO>(productEntity);
|
- 使用实例方法
1
2
3
|
MapperConfiguration configuration =
new
MapperConfiguration(cfg => cfg.CreateMap<ProductEntity, ProductDTO>());
var
mapper = configuration.CreateMapper();
var
productDTO = mapper.Map<ProductDTO>(productEntity);
|
完整的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
[TestMethod]
public
void
TestInitialization()
{
var
productEntity =
new
ProductEntity()
{
Name =
"Product"
+ DateTime.Now.Ticks,
Amount = 10
};
Mapper.Initialize(cfg => cfg.CreateMap<ProductEntity, ProductDTO>());
var
productDTO = Mapper.Map<ProductDTO>(productEntity);
Assert.IsNotNull(productDTO);
Assert.IsNotNull(productDTO.Name);
Assert.IsTrue(productDTO.Amount > 0);
}
|
Profiles设置
除了使用以上两总方式类配置映射关系,也可以使用Profie配置来实现映射关系。
创建自定义的Profile需要继承Profile类:
1
2
3
4
5
6
7
8
|
public
class
MyProfile : Profile
{
public
MyProfile()
{
CreateMap<ProductEntity, ProductDTO>();
// Other mapping configurations
}
}
|
完成例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
[TestMethod]
public
void
TestProfile()
{
var
productEntity =
new
ProductEntity()
{
Name =
"Product"
+ DateTime.Now.Ticks,
Amount = 10
};
var
configuration =
new
MapperConfiguration(cfg => cfg.AddProfile<MyProfile>());
var
productDTO = configuration.CreateMapper().Map<ProductDTO>(productEntity);
Assert.IsNotNull(productDTO);
Assert.IsNotNull(productDTO.Name);
Assert.IsTrue(productDTO.Amount > 0);
}
|
除了使用AddProfile,也可以使用AddProfiles添加多个配置;同样,可以同时使用Mapper和Profile,也可以添加多个配置:
1
2
3
4
5
|
var
configuration =
new
MapperConfiguration(cfg =>
{
cfg.AddProfile<MyProfile>();
cfg.CreateMap<ProductEntity, ProductDTO>();
});
|
扁平化映射
AutoMapper先映射名字一致的字段,如果没有,则会尝试使用以下规则来映射:
- 目标中字段去掉前缀“Get”后的部分
- 分割目标字段(根据Pascal命名方式)为单个单词
先创建用到的映射类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public
class
Product
{
public
Supplier Supplier {
get
;
set
; }
public
string
Name {
get
;
set
; }
public
decimal
GetAmount()
{
return
10;
}
}
public
class
Supplier
{
public
string
Name {
get
;
set
; }
}
public
class
ProductDTO
{
public
string
SupplierName {
get
;
set
; }
public
decimal
Amount {
get
;
set
; }
}
|
AutoMapper会自动实现Product.Supplier.Name -> ProductDTO.SupplierName, Product.GetTotal -> ProductDTO.Total的映射。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
[TestMethod]
public
void
TestFalttening()
{
var
supplier =
new
Supplier()
{
Name =
"Supplier"
+ DateTime.Now.Ticks
};
var
product =
new
Product()
{
Supplier = supplier,
Name =
"Product"
+ DateTime.Now.Ticks
};
Mapper.Initialize(cfg => cfg.CreateMap<Product, ProductDTO>());
var
productDTO = Mapper.Map<ProductDTO>(product);
Assert.IsNotNull(productDTO);
Assert.IsNotNull(productDTO.SupplierName);
Assert.IsTrue(productDTO.Amount > 0);
}
|
集合验证
AutoMapper除了可以映射单个对象外,也可以映射集合对象。AutoMapper源集合类型支持以下几种:
- IEnumerable
- IEnumerable<T>
- ICollection
- ICollection<T>
- IList
- IList<T>
- List<T>
- Arrays
简单类型映射:
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
|
public
class
Source
{
public
int
Value {
get
;
set
; }
}
public
class
Destination
{
public
int
Value {
get
;
set
; }
}
[TestMethod]
public
void
TestCollectionSimple()
{
Mapper.Initialize(cfg => cfg.CreateMap<Source, Destination>());
var
sources =
new
[]
{
new
Source {Value = 1},
new
Source {Value = 2},
new
Source {Value = 3}
};
IEnumerable<Destination> ienumerableDest = Mapper.Map<Source[], IEnumerable<Destination>>(sources);
ICollection<Destination> icollectionDest = Mapper.Map<Source[], ICollection<Destination>>(sources);
IList<Destination> ilistDest = Mapper.Map<Source[], IList<Destination>>(sources);
List<Destination> listDest = Mapper.Map<Source[], List<Destination>>(sources);
Destination[] arrayDest = Mapper.Map<Source[], Destination[]>(sources);
}
|
复杂对象映射:
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
|
public
class
Order
{
private
IList<OrderLine> _lineItems =
new
List<OrderLine>();
public
OrderLine[] LineItems {
get
{
return
_lineItems.ToArray(); } }
public
void
AddLineItem(OrderLine orderLine)
{
_lineItems.Add(orderLine);
}
}
public
class
OrderLine
{
public
int
Quantity {
get
;
set
; }
}
public
class
OrderDTO
{
public
OrderLineDTO[] LineItems {
get
;
set
; }
}
public
class
OrderLineDTO
{
public
int
Quantity {
get
;
set
; }
}
[TestMethod]
public
void
TestCollectionNested()
{
Mapper.Initialize(cfg =>
{
cfg.CreateMap<Order, OrderDTO>();
cfg.CreateMap<OrderLine, OrderLineDTO>();
});
var
order =
new
Order();
order.AddLineItem(
new
OrderLine {Quantity = 10});
order.AddLineItem(
new
OrderLine {Quantity = 20});
order.AddLineItem(
new
OrderLine {Quantity = 30});
var
orderDTO = Mapper.Map<OrderDTO>(order);
Assert.IsNotNull(orderDTO);
Assert.IsNotNull(orderDTO.LineItems);
Assert.IsTrue(orderDTO.LineItems.Length > 0);
}
|
投影及条件映射
投影(指定字段)
除了以上使用的自动映射规则,AutoMapper还可以指定映射方式。下面使用ForMemeber指定字段的映射,将一个时间值拆分映射到日期、时、分:
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
|
public
class
Calendar
{
public
DateTime CalendarDate {
get
;
set
; }
public
string
Title {
get
;
set
; }
}
public
class
CalendarModel
{
public
DateTime Date {
get
;
set
; }
public
int
Hour {
get
;
set
; }
public
int
Minute {
get
;
set
; }
public
string
Title {
get
;
set
; }
}
[TestMethod]
public
void
TestProjection()
{
var
calendar =
new
Calendar()
{
Title =
"2018年日历"
,
CalendarDate =
new
DateTime(2018, 1, 1, 11, 59, 59)
};
Mapper.Initialize(cfg => cfg
.CreateMap<Calendar, CalendarModel>()
.ForMember(dest => dest.Date, opt => opt.MapFrom(src =>src.CalendarDate.Date))
.ForMember(dest => dest.Hour, opt => opt.MapFrom(src => src.CalendarDate.Hour))
.ForMember(dest => dest.Minute, opt => opt.MapFrom(src => src.CalendarDate.Minute)));
var
calendarModel = Mapper.Map<CalendarModel>(calendar);
Assert.AreEqual(calendarModel.Date.Ticks,
new
DateTime(2018, 1, 1).Ticks);
Assert.AreEqual(calendarModel.Hour, 11);
Assert.AreEqual(calendarModel.Minute, 59);
}
|
条件映射
有些情况下,我们会考虑添加映射条件,比如,某个值不符合条件时,不允许映射。针对这种情况可以使用ForMember中的Condition:
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
|
public
class
Source
{
public
int
Value {
get
;
set
; }
}
public
class
Destination
{
public
uint
Value {
get
;
set
; }
}
[TestMethod]
public
void
TestConditionByCondition()
{
var
source =
new
Source()
{
Value = 3
};
//如果Source.Value > 0, 则执行映射;否则,映射失败
Mapper.Initialize(cfg => cfg
.CreateMap<Source, Destination>()
.ForMember(dest => dest.Value, opt => opt.Condition(src => src.Value > 0)));
var
destation = Mapper.Map<Destination>(source);
//如果不符合条件,则抛出异常
Assert.IsTrue(destation.Value.Equals(3));
}
|
如果要映射的类符合一定的规则,而且有很多,针对每个类都创建一个CreaterMapper会很麻烦。可以使用AddConditionalObjectMapper指定对象映射规则,这样就不用每个映射关系都添加一个CreateMapper。另外,也可以使用AddMemberConfiguration指定字段的映射规则,比如字段的前后缀:
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
|
public
class
Product
{
public
string
Name {
get
;
set
; }
public
int
Count {
get
;
set
; }
}
public
class
ProductModel
{
public
string
NameModel {
get
;
set
; }
public
int
CountMod {
get
;
set
; }
}
[TestMethod]
public
void
TestConditionByConfiguration()
{
var
product =
new
Product()
{
Name =
"Product"
+ DateTime.Now.Ticks,
Count = 10
};
var
config =
new
MapperConfiguration(cfg =>
{
//对象映射规则: 通过以下配置,可以映射所有”目标对象的名称“等于“源对象名称+Model”的类,而不用单个添加CreateMapper映射
cfg.AddConditionalObjectMapper().Where((s, d) => d.Name == s.Name +
"Model"
);
//字段映射规则: 通过以下配置,可以映射“源字段”与“目标字段+Model或Mod”的字段
cfg.AddMemberConfiguration().AddName<PrePostfixName>(_ => _.AddStrings(p => p.DestinationPostfixes,
"Model"
,
"Mod"
));
});
var
mapper = config.CreateMapper();
var
productModel = mapper.Map<ProductModel>(product);
Assert.IsTrue(productModel.CountMod == 10);
}
|
需要注意的一点是,添加了以上配置,如果目标对象中有字段没有映射到,则会抛出异常。
值转换
如果配置了值转换,AutoMapper会将修改转换后的值以符合配置的规则。比如,配置目标对象中的值添加符号“@@”:
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
|
public
class
Source
{
public
string
Name {
get
;
set
; }
}
public
class
Destination
{
public
string
Name {
get
;
set
; }
}
[TestMethod]
public
void
TestValueTransfer()
{
var
source =
new
Source()
{
Name =
"Bob"
};
Mapper.Initialize(cfg =>
{
cfg.CreateMap<Source, Destination>();
cfg.ValueTransformers.Add<
string
>(val =>
string
.Format(
"@{0}@"
, val));
});
var
destation = Mapper.Map<Destination>(source);
Assert.AreEqual(
"@Bob@"
, destation.Name);
}
|
空值替换
如果要映射的值为Null,则可以使用NullSubstitute指定Null值的替换值:
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
|
public
class
Source
{
public
string
Name {
get
;
set
; }
}
public
class
Destination
{
public
string
Name {
get
;
set
; }
}
[TestMethod]
public
void
TestValueTransfer()
{
var
source =
new
Source()
{
};
Mapper.Initialize(cfg =>
{
cfg.CreateMap<Source, Destination>()
.ForMember(dest => dest.Name, opt => opt.NullSubstitute(
"其他值"
));
});
var
destation = Mapper.Map<Destination>(source);
Assert.AreEqual(
"其他值"
, destation.Name);
}
|
配置验证及设置
配置了映射,但是如何确定是否映射成功或者是否有字段没有映射呢?可以添加Mapper.AssertConfigurationIsValid();来验证是否映射成功。默认情况下,目标对象中的字段都被映射到后,AssertConfigurationIsValid才会返回True。也就是说,源对象必须包含所有目标对象,这样在大多数情况下不是我们想要的,我们可以使用下面的方法来指定验证规则:
- 指定单个字段不验证
- 指定整个Map验证规则
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
|
public
class
Product
{
public
string
Name {
get
;
set
; }
public
int
Amount {
get
;
set
; }
}
public
class
ProductModel
{
public
string
Name {
get
;
set
; }
public
int
Amount {
get
;
set
; }
public
string
ViewName {
get
;
set
; }
}
public
class
ProductDTO
{
public
string
Name {
get
;
set
; }
public
int
Amount {
get
;
set
; }
public
string
ViewName {
get
;
set
; }
}
[TestMethod]
public
void
TestValidation()
{
var
product =
new
Product()
{
Name =
"Product"
+ DateTime.Now.Ticks,
Amount = 10
};
Mapper.Initialize(cfg =>
{
//1. 指定字段映射方式
cfg.CreateMap<Product, ProductModel>()
.ForMember(dest => dest.ViewName, opt => opt.Ignore());
//如果不添加此设置,会抛出异常
//2. 指定整个对象映射方式
//MemberList:
// Source: 检查源对象所有字段映射成功
// Destination:检查目标对象所有字段映射成功
// None: 跳过验证
cfg.CreateMap<Product, ProductDTO>(MemberList.Source);
});
var
productModel = Mapper.Map<ProductModel>(product);
var
productDTO = Mapper.Map<ProductDTO>(product);
//验证映射是否成功
Mapper.AssertConfigurationIsValid();
}
|
设置转换前后行为
有的时候你可能会在创建映射前后对数据做一些处理,AutoMapper就提供了这种方式:
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
|
public
class
Source
{
public
string
Name {
get
;
set
; }
public
int
Value {
get
;
set
; }
}
public
class
Destination
{
public
string
Name {
get
;
set
; }
public
int
Value {
get
;
set
; }
}
[TestMethod]
public
void
TestBeforeOrAfter()
{
var
source =
new
Source()
{
Name =
"Product"
+ DateTime.Now.Ticks,
};
Mapper.Initialize(cfg =>
{
cfg.CreateMap<Source, Destination>()
.BeforeMap((src, dest) => src.Value = src.Value + 10)
.AfterMap((src, dest) => dest.Name =
"Pobin"
);
});
var
productModel = Mapper.Map<Destination>(source);
Assert.AreEqual(
"Pobin"
, productModel.Name);
}
|
反向映射
从6.1.0开始,AutoMapper通过调用Reverse可以实现反向映射。反向映射根据初始化时创建的正向映射规则来做反向映射:
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
|
public
class
Order
{
public
decimal
Total {
get
;
set
; }
public
Customer Customer {
get
;
set
; }
}
public
class
Customer
{
public
string
Name {
get
;
set
; }
}
public
class
OrderDTO
{
public
decimal
Total {
get
;
set
; }
public
string
CustomerName {
get
;
set
; }
}
[TestMethod]
public
void
TestReverseMapping()
{
var
customer =
new
Customer
{
Name =
"Tom"
};
var
order =
new
Order
{
Customer = customer,
Total = 20
};
Mapper.Initialize(cfg => {
cfg.CreateMap<Order, OrderDTO>()
.ForMember(dest => dest.CustomerName, opt => opt.MapFrom(src => src.Customer.Name))
//正向映射规则
.ReverseMap();
//设置反向映射
});
//正向映射
var
orderDTO = Mapper.Map<OrderDTO>(order);
//反向映射:使用ReverseMap,不用再创建OrderDTO -> Order的映射,而且还能保留正向的映射规则
var
orderConverted = Mapper.Map<Order>(orderDTO);
Assert.IsNotNull(orderConverted.Customer);
Assert.AreEqual(
"Tom"
, orderConverted.Customer.Name);
}
|
如果反向映射中不想使用原先的映射规则,也可以取消掉:
1
2
3
4
5
6
|
Mapper.Initialize(cfg => {
cfg.CreateMap<Order, OrderDTO>()
.ForMember(dest => dest.CustomerName, opt => opt.MapFrom(src => src.Customer.Name))
//正向映射规则
.ReverseMap()
.ForPath(src => src.Customer.Name, opt => opt.Ignore());
//设置反向映射
});
|
自定义转换器
有些情况下目标字段类型和源字段类型不一致,可以通过类型转换器实现映射,类型转换器有三种实现方式:
1
2
3
|
void
ConvertUsing(Func<TSource, TDestination> mappingFunction);
void
ConvertUsing(ITypeConverter<TSource, TDestination> converter);
void
ConvertUsing<TTypeConverter>()
where
TTypeConverter : ITypeConverter<TSource, TDestination>;
|
下面通过一个例子来演示下以上三种类型转换器的使用方式:
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
59
60
61
62
|
namespace
AutoMapperSummary
{
[TestClass]
public
class
CustomerTypeConvert
{
public
class
Source
{
public
string
Value1 {
get
;
set
; }
public
string
Value2 {
get
;
set
; }
public
string
Value3 {
get
;
set
; }
}
public
class
Destination
{
public
int
Value1 {
get
;
set
; }
public
DateTime Value2 {
get
;
set
; }
public
Type Value3 {
get
;
set
; }
}
public
class
DateTimeTypeConverter : ITypeConverter<
string
, DateTime>
{
public
DateTime Convert(
string
source, DateTime destination, ResolutionContext context)
{
return
System.Convert.ToDateTime(source);
}
}
public
class
TypeTypeConverter : ITypeConverter<
string
, Type>
{
public
Type Convert(
string
source, Type destination, ResolutionContext context)
{
return
Assembly.GetExecutingAssembly().GetType(source);
}
}
[TestMethod]
public
void
TestTypeConvert()
{
var
config =
new
MapperConfiguration(cfg =>
{
cfg.CreateMap<
string
,
int
>().ConvertUsing((
string
s) => Convert.ToInt32(s));
cfg.CreateMap<
string
, DateTime>().ConvertUsing(
new
DateTimeTypeConverter());
cfg.CreateMap<
string
, Type>().ConvertUsing<TypeTypeConverter>();
cfg.CreateMap<Source, Destination>();
});
config.AssertConfigurationIsValid();
//验证映射是否成功
var
source =
new
Source
{
Value1 =
"20"
,
Value2 =
"2018/1/1"
,
Value3 =
"AutoMapperSummary.CustomerTypeConvert+Destination"
};
var
mapper = config.CreateMapper();
var
destination = mapper.Map<Source, Destination>(source);
Assert.AreEqual(
typeof
(Destination), destination.Value3);
}
}
}
|
自定义解析器
使用AutoMapper的自带解析规则,我们可以很方便的实现对象的映射。比如:源/目标字段名称一致,“Get/get + 源字段“与"目标字段"一致等。除了这些简单的映射,还可以使用ForMember指定字段映射。但是,某些情况下,解析规则会很复杂,使用自带的解析规则无法实现。这时可以自定义解析规则,可以通过以下三种方式使用自定义的解析器:
1
2
3
|
ResolveUsing<TValueResolver>
ResolveUsing(
typeof
(CustomValueResolver))
ResolveUsing(aValueResolverInstance)
|
下面通过一个例子来演示如何使用自定义解析器:
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
|
public
class
Source
{
public
string
FirstName {
get
;
set
; }
public
string
LastName {
get
;
set
; }
}
public
class
Destination
{
public
string
Name {
get
;
set
; }
}
/// <summary>
/// 自定义解析器: 组合姓名
/// </summary>
public
class
CustomResolver : IValueResolver<Source, Destination,
string
>
{
public
string
Resolve(Source source, Destination destination,
string
destMember, ResolutionContext context)
{
if
(source !=
null
&& !
string
.IsNullOrEmpty(source.FirstName) && !
string
.IsNullOrEmpty(source.LastName))
{
return
string
.Format(
"{0} {1}"
, source.FirstName, source.LastName);
}
return
string
.Empty;
}
}
[TestMethod]
public
void
TestResolver()
{
Mapper.Initialize(cfg =>
cfg.CreateMap<Source, Destination>()
.ForMember(dest => dest.Name, opt => opt.ResolveUsing<CustomResolver>()));
Mapper.AssertConfigurationIsValid();
var
source =
new
Source
{
FirstName =
"Michael"
,
LastName =
"Jackson"
};
var
destination = Mapper.Map<Source, Destination>(source);
Assert.AreEqual(
"Michael Jackson"
, destination.Name);
}
|
AutoMapper封装
AutoMapper功能很强大,自定义配置支持也非常好,但是真正项目中使用时却很少用到这么多功能,而且一般都会对AutoMapper进一步封装使用。一方面使用起来方面,另外一方面也可以使代码统一。下面的只是做一个简单的封装,还需要结合实际项目使用:
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
/// <summary>
/// AutoMapper帮助类
/// </summary>
public
class
AutoMapperManager
{
private
static
readonly
MapperConfigurationExpression MapperConfiguration =
new
MapperConfigurationExpression();
static
AutoMapperManager()
{
}
private
AutoMapperManager()
{
AutoMapper.Mapper.Initialize(MapperConfiguration);
}
public
static
AutoMapperManager Instance {
get
; } =
new
AutoMapperManager();
/// <summary>
/// 添加映射关系
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TDestination"></typeparam>
public
void
AddMap<TSource, TDestination>()
where
TSource :
class
,
new
()
where
TDestination :
class
,
new
()
{
MapperConfiguration.CreateMap<TSource, TDestination>();
}
/// <summary>
/// 获取映射值
/// </summary>
/// <typeparam name="TDestination"></typeparam>
/// <param name="source"></param>
/// <returns></returns>
public
TDestination Map<TDestination>(
object
source)
where
TDestination :
class
,
new
()
{
if
(source ==
null
)
{
return
default
(TDestination);
}
return
Mapper.Map<TDestination>(source);
}
/// <summary>
/// 获取集合映射值
/// </summary>
/// <typeparam name="TDestination"></typeparam>
/// <param name="source"></param>
/// <returns></returns>
public
IEnumerable<TDestination> Map<TDestination>(IEnumerable source)
where
TDestination :
class
,
new
()
{
if
(source ==
null
)
{
return
default
(IEnumerable<TDestination>);
}
return
Mapper.Map<IEnumerable<TDestination>>(source);
}
/// <summary>
/// 获取映射值
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TDestination"></typeparam>
/// <param name="source"></param>
/// <returns></returns>
public
TDestination Map<TSource, TDestination>(TSource source)
where
TSource :
class
,
new
()
where
TDestination :
class
,
new
()
{
if
(source ==
null
)
{
return
default
(TDestination);
}
return
Mapper.Map<TSource, TDestination>(source);
}
/// <summary>
/// 获取集合映射值
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TDestination"></typeparam>
/// <param name="source"></param>
/// <returns></returns>
public
IEnumerable<TDestination> Map<TSource, TDestination>(IEnumerable<TSource> source)
where
TSource :
class
,
new
()
where
TDestination :
class
,
new
()
{
if
(source ==
null
)
{
return
default
(IEnumerable<TDestination>);
}
return
Mapper.Map<IEnumerable<TSource>, IEnumerable<TDestination>>(source);
}
/// <summary>
/// 读取DataReader内容
/// </summary>
/// <typeparam name="TDestination"></typeparam>
/// <param name="reader"></param>
/// <returns></returns>
public
IEnumerable<TDestination> Map<TDestination>(IDataReader reader)
{
if
(reader ==
null
)
{
return
new
List<TDestination>();
}
var
result = Mapper.Map<IEnumerable<TDestination>>(reader);
if
(!reader.IsClosed)
{
reader.Close();
}
return
result;
}
}
|
总结
本篇文章列举了AutoMapper的基本使用方式,更多的使用可以参考官方文档:http://automapper.readthedocs.io/en/latest/index.html