AutoMapper 使用总结1

简介: 原文:AutoMapper 使用总结1初识AutoMapper 在开始本篇文章之前,先来思考一个问题:一个项目分多层架构,如显示层、业务逻辑层、服务层、数据访问层。层与层访问需要数据载体,也就是类。
原文: AutoMapper 使用总结1

初识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

目录
相关文章
|
前端开发
8分钟学会使用AutoMapper
原文:8分钟学会使用AutoMapper 一.什么是AutoMapper与为什么用它。 它是一种对象与对象之间的映射器,让AutoMapper有意思的就是在于它提供了一些将类型A映射到类型B这种无聊的实例,只要B遵循AutoMapper已经建立的惯例,那么大多数情况下就可以进行相互映射了。
1009 0
|
测试技术 容器