DTO即数据传输对象。
简单来说Model面向业务,我们是通过业务来定义Model的。而DTO是面向界面UI,是通过UI的需求来定义的。通过DTO我们实现了表现层与Model之间的解耦,表现层不引用Model,如果开发过程中我们的模型改变了,而界面没变,我们就只需要改Model而不需要去改表现层中的东西。
一、最简单的用法
有两个类User和UserDto
public class User { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } } public class UserDto { public string Name { get; set; } public int Age { get; set; } }
将User转换成UserDto也和简单
Mapper.Initialize(x => x.CreateMap<User, UserDto>()); User user = new User() { Id = 1, Name = "caoyc", Age = 20 }; var dto = Mapper.Map<UserDto>(user);
这是一种最简单的使用,AutoMapper会根据字段名称去自动对于,忽略大小写。
二、如果属性名称不同
将UserDto的Name属性改成Name2
Mapper.Initialize(x => x.CreateMap<User, UserDto>() .ForMember(d =>d.Name2, opt => { opt.MapFrom(s => s.Name); }) ); User user = new User() { Id = 1, Name = "caoyc", Age = 20 }; var dto = Mapper.Map<UserDto>(user);
三、使用Profile配置
自定义一个UserProfile类继承Profile,并重写Configure方法
public class UserProfile : Profile { protected override void Configure() { CreateMap<User, UserDto>().ForMember(d => d.Name2, opt => { opt.MapFrom(s => s.Name); }); } }
使用时就这样
Mapper.Initialize(x => x.AddProfile<UserProfile>()); User user = new User() { Id = 1, Name = "caoyc", Age = 20 }; var dto = Mapper.Map<UserDto>(user);
四、空值替换NullSubstitute
空值替换允许我们将Source对象中的空值在转换为Destination的值的时候,使用指定的值来替换空值。
public class UserProfile : Profile { protected override void Configure() { CreateMap<User, UserDto>() .ForMember(d => d.Name2, opt => opt.MapFrom(s => s.Name)) .ForMember(d => d.Name2, opt => opt.NullSubstitute("值为空")); } }
Mapper.Initialize(x => x.AddProfile<UserProfile>()); User user = new User() { Id = 1, Age = 20 }; var dto = Mapper.Map<UserDto>(user);
结果为:
五、忽略属性Ignore
public class User { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } } public class UserDto { public string Name { get; set; } public int Age { get; set; } } public class UserProfile : Profile { protected override void Configure() { CreateMap<User, UserDto>().ForMember("Name", opt => opt.Ignore()); } }
使用
Mapper.Initialize(x => x.AddProfile<UserProfile>()); User user = new User() { Id = 1, Name="caoyc", Age = 20 }; var dto = Mapper.Map<UserDto>(user);
结果:
六、预设值
如果目标属性多于源属性,可以进行预设值
public class User { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } } public class UserDto { public string Name { get; set; } public int Age { get; set; } public string Gender { get; set; } } public class UserProfile : Profile { protected override void Configure() { CreateMap<User, UserDto>(); } }
使用
Mapper.Initialize(x => x.AddProfile<UserProfile>()); User user = new User() { Id = 1, Name="caoyc", Age = 20 }; UserDto dto = new UserDto() {Gender = "男"}; Mapper.Map(user, dto);
七、类型转换ITypeConverter
如果数据中Gender存储的int类型,而DTO中Gender是String类型
public class User { public int Gender { get; set; } } public class UserDto { public string Gender { get; set; } }
类型转换类,需要实现接口ITypeConverter
public class GenderTypeConvertert : ITypeConverter<int, string> { public string Convert(int source, string destination, ResolutionContext context) { switch (source) { case 0: destination = "男"; break; case 1: destination = "女"; break; default: destination = "未知"; break; } return destination; } }
配置规则
public class UserProfile : Profile { protected override void Configure() { CreateMap<User, UserDto>(); CreateMap<int, string>().ConvertUsing<GenderTypeConvertert>(); //也可以写这样 //CreateMap<int, string>().ConvertUsing(new GenderTypeConvertert()); } }
使用
Mapper.Initialize(x => x.AddProfile<UserProfile>()); User user0 = new User() { Gender = 0 }; User user1 = new User() { Gender = 1 }; User user2 = new User() { Gender = 2 }; var dto0= Mapper.Map<UserDto>(user0); var dto1 = Mapper.Map<UserDto>(user1); var dto2 = Mapper.Map<UserDto>(user2); Console.WriteLine("dto0:{0}", dto0.Gender); Console.WriteLine("dto1:{0}", dto1.Gender); Console.WriteLine("dto2:{0}", dto2.Gender);
结果
八、条件约束Condition
当满足条件时才进行映射字段,例如人类年龄,假设我们现在人类年龄范围为0-200岁(这只是假设),只有满足在这个条件才进行映射
public class User { public int Age { get; set; } } public class UserDto { public int Age { get; set; } }
Profile
public class UserProfile : Profile { protected override void Configure() { CreateMap<User, UserDto>().ForMember(dest=>dest.Age,opt=>opt.Condition(src=>src.Age>=0 && src.Age<=200)); } }
使用代码
Mapper.Initialize(x => x.AddProfile<UserProfile>()); User user0 = new User() { Age = 1 }; User user1 = new User() { Age = 150 }; User user2 = new User() { Age = 201 }; var dto0= Mapper.Map<UserDto>(user0); var dto1 = Mapper.Map<UserDto>(user1); var dto2 = Mapper.Map<UserDto>(user2); Console.WriteLine("dto0:{0}", dto0.Age); Console.WriteLine("dto1:{0}", dto1.Age); Console.WriteLine("dto2:{0}", dto2.Age);
输出结果
倘若在项目中真正要用的时候,我觉得还是应该对AutoMapper的方法进行一些整理,最好能够封装一下,这里我通过扩展方法的形式将其封装为AutoMapperHelper,这样以后使用AutoMapper就变的SO EASY了~
using System.Collections; using System.Collections.Generic; using System.Data; using AutoMapper; namespace Infrastructure.Utility { /// <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); } } }
你可以像下面的栗子这样使用:
//对象映射 ShipInfoModel shipInfoModel = ShipInfo.MapTo<ShipInfoModel>(); //列表映射 List< ShipInfoModel > shipInfoModellist = ShipInfoList.MapToList<ShipInfoModel>();