一、为什么要用AutoMapper
AutoMapper是一个 对象 - 对象映射器 。对象 - 对象映射的工作原理是将一种类型的输入对象转换为另一种类型的输出对象。
一个项目分多层架构,如UI层、业务逻辑层、服务层、数据访问层。层与层访问需要数据载体,也就是类。如果多层通用一个类,一则会暴露出每层的字段,二者会使类字段很多,而且会出现很多冗余字段,这种方式是不可取的;如果每层都使用不同的类,则层与层调用时,一个字段一个字段的赋值又会很麻烦。使用AutoMapper可以帮助我们实现类字段的赋值及转换,AutoMapper提供了映射规则及操作方法,使我们不用过多配置就可以映射两个类。
二、AutoMapper简单使用
先创建两个类用于映射:
//用户类 Source public class UserInfo { public string Name { get; set; } public int Age { get; set; } } //用户类 destination public class UserInfoDTO { public string Name { get; set; } public int Age { get; set; } }
2.1 简单创建映射
Automapper可以使用静态类和实例方法来创建映射,下面分别使用这两种方式来实现 UserInfo-> UserInfoDTO的映射。
- 使用静态方式(使用
MapperConfiguration
在AppDomain通常只需要一个实例,并且应该在启动期间进行实例化。)//静态方式创建映射 Mapper.Initialize(cfg => cfg.CreateMap<UserInfo, UserInfoDTO>()); var userInfoDTO1 = Mapper.Map<UserInfoDTO>(userInfo);
- 使用实例方法
//实例方法创建映射 MapperConfiguration configuration = new MapperConfiguration(cfg => cfg.CreateMap<UserInfo, UserInfoDTO>()); var mapper = configuration.CreateMapper(); var userInfoDTO2 = mapper.Map<UserInfoDTO>(userInfo);
完整的例子:
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 //Souce 6 UserInfo userInfo = new UserInfo() { Name = "tom", Age = 22 }; 7 8 //静态方式创建映射 9 Mapper.Initialize(cfg => cfg.CreateMap<UserInfo, UserInfoDTO>()); 10 var userInfoDTO1 = Mapper.Map<UserInfoDTO>(userInfo); 11 12 //实例方法创建映射 13 MapperConfiguration configuration = new MapperConfiguration(cfg => cfg.CreateMap<UserInfo, UserInfoDTO>()); 14 var mapper = configuration.CreateMapper(); 15 var userInfoDTO2 = mapper.Map<UserInfoDTO>(userInfo); 16 17 Console.WriteLine("用户映射1 名字为{0},年龄是{1}", userInfoDTO1.Name, userInfoDTO1.Age); 18 Console.WriteLine("用户映射2 名字为{0},年龄是{1}", userInfoDTO2.Name, userInfoDTO2.Age); 19 Console.ReadKey(); 20 } 21 }
2.2 配置(Profie)实现映射关系
当需要配置的映射关系较多时,使用上边的方式一个一个添加映射关系很不方便,我们可以使用Profile来实现映射关系。
第一步.创建自定义的Profile需要继承Profile类:
public class MyProfile:Profile { public MyProfile() { CreateMap<RoleInfo, RoleInfoDTO>(); CreateMap<UserInfo, UserInfoDTO>(); } }
第二步.实现配置:
1 static void Main(string[] args) 2 { 3 //Souce 4 UserInfo userInfo = new UserInfo() { Name = "tom", Age = 22 }; 5 RoleInfo roleInfo = new RoleInfo() { RoleId = 1, RoleName = "管理员" }; 6 7 //配置的方式实现DTO 8 var configuration = new MapperConfiguration(cfg => cfg.AddProfile<MyProfile>()); 9 var roleInfoDTO = configuration.CreateMapper().Map<RoleInfoDTO>(roleInfo); 10 var userInfoDTO = configuration.CreateMapper().Map<UserInfoDTO>(userInfo); 11 12 13 Console.WriteLine("角色映射 Id为{0},角色名是{1}", roleInfoDTO.RoleId, roleInfoDTO.RoleName); 14 Console.WriteLine("用户映射 名字为{0},年龄是{1}", userInfoDTO.Name, userInfoDTO.Age); 15 Console.ReadKey(); 16 }
常用的方式:我们可以同时使用Mapper和Profile,也可以添加多个配置,如下边的Configuration2所示(通过这种方式很容易进行封装):
static void Main(string[] args) { //Souce UserInfo userInfo = new UserInfo() { Name = "tom", Age = 22 }; RoleInfo roleInfo = new RoleInfo() { RoleId = 1, RoleName = "管理员" }; //配置的方式实现DTO var configuration = new MapperConfiguration(cfg => cfg.AddProfile<MyProfile>()); var configuration2 = new MapperConfiguration(cfg => { cfg.AddProfile<MyProfile>(); cfg.CreateMap<ProductEntity, ProductDTO>(); //...可以有很多 }); var roleInfoDTO = configuration.CreateMapper().Map<RoleInfoDTO>(roleInfo); var userInfoDTO = configuration.CreateMapper().Map<UserInfoDTO>(userInfo); Console.WriteLine("角色映射 Id为{0},角色名是{1}", roleInfoDTO.RoleId, roleInfoDTO.RoleName); Console.WriteLine("用户映射 名字为{0},年龄是{1}", userInfoDTO.Name, userInfoDTO.Age); Console.ReadKey(); }
2.3 属性不同名/反向映射
还是上边的UserInfo和UserInfoDTO的例子,如果UserInfo中的Name属性变成UName,那么我们怎样实现映射:UserInfo.UName->UserInfoDTO.Name?方法也很简单,直接上代码
1 static void Main(string[] args) 2 { 3 Mapper.Initialize(cfg => 4 { 5 //UserInfo中的属性Name改为UName,那么可以进行以下设置 6 cfg.CreateMap<UserInfo, UserInfoDTO>() 7 .ForMember(d => d.Name, opt => 8 { 9 opt.MapFrom(s => s.UName); 10 });//.ReverseMap();注册映射关系的时候,加上这句就可以就进行双向映射了 11 }); 12 13 //不加 ReverseMap(),只能从UserInfo->UserInfoDTO,下边代码会抛异常(没有UserInfoDTO->UserInfo的映射) 14 UserInfoDTO userDto = new UserInfoDTO(){Name = "貂蝉",Age = 20}; 15 var user = Mapper.Map<UserInfo>(userDto); 16 17 UserInfo user2 = new UserInfo { UName = "刘备", Age = 30 }; 18 var user2Dto = Mapper.Map<UserInfoDTO>(user2); 19 20 Console.WriteLine(user.UName); 21 Console.WriteLine(user2Dto.Name); 22 Console.ReadKey(); 23 }
2.4 集合和数组的映射
AutoMapper only requires configuration of element types, not of any array or list type that might be used.
AutoMapper只需要配置元素的类型,不用配置数值/列表的类型。配置了元素类型,我们可以转换为IEnumerable / ICollection / IList / List/ Arrays中的任一种类型
1 public class Source 2 { 3 public int Value { get; set; } 4 } 5 public class Destination 6 { 7 public int Value { get; set; } 8 } 9 //-----------------------------------------------// 10 class Program 11 { 12 static void Main(string[] args) 13 { 14 //只配置元素的类型 15 var configuration = new MapperConfiguration(cfg => 16 { 17 cfg.CreateMap<Source, Destination>().ReverseMap(); 18 }); 19 20 var sources = new[] 21 { 22 new Source { Value = 5 }, 23 new Source { Value = 6 }, 24 new Source { Value = 7 } 25 }; 26 //可以转为很多格式 27 IEnumerable<Destination> ienumerableDest = configuration.CreateMapper().Map<Source[], IEnumerable<Destination>>(sources); 28 ICollection<Destination> icollectionDest = configuration.CreateMapper().Map<Source[], ICollection<Destination>>(sources); 29 IList<Destination> ilistDest = configuration.CreateMapper().Map<Source[], IList<Destination>>(sources); 30 List<Destination> listDest = configuration.CreateMapper().Map<Source[], List<Destination>>(sources); 31 Destination[] arrayDest = configuration.CreateMapper().Map<Source[], Destination[]>(sources); 32 33 Console.WriteLine(ienumerableDest.All(s => s.Value >= 5)); 34 Console.ReadKey(); 35 } 36 }
这里只记录了一些AutoMapper的简单使用方法,更多功能可以参考官方文档:http://automapper.readthedocs.io/en/latest/Lists-and-arrays.html