先说一说DTO
DTO是个什么东东?
DTO(Data Transfer Object)就是数据传输对象,说白了就是一个对象,只不过里边全是数据而已。
为什么要用DTO?
1、DTO更注重数据,对领域对象进行合理封装,从而不会将领域对象的行为过分暴露给表现层
2、DTO是面向UI的需求而设计的,而领域模型是面向业务而设计的。因此DTO更适合于和表现层的交互,通过DTO我们实现了表现层与领域Model之间的解耦,因此改动领域Model不会影响UI层
3、DTO说白了就是数据而已,不包含任何的业务逻辑,属于瘦身型的对象,使用时可以根据不同的UI需求进行灵活的运用
AutoMapper
现在我们既然知道了使用DTO的好处,那么我们肯定也想马上使用它,但是这里会牵扯一个问题:怎样实现DTO和领域Model之间的转换?
有两个思路,我们要么自己写转换代码,要么使用工具。不过就应用而言,我还是觉得用工具比较简单快捷,那就使用工具吧。其实这样的转换工具很多,不过我还是决定使用AutoMapper,因为它足够轻量级,而且也非常流行,国外的大牛们都使用它。使用AutoMapper可以很方便的实现DTO和领域Model之间的转换,它是一个强大的Object-Object Mapping工具。
一、如何添加AutoMapper到项目中?
在vs中使用打开工具-库程序包管理器-程序包管理控制平台,输入“Install-Package AutoMapper”命令,就可以把AutoMapper添加到项目中了~
二、吃点栗子
栗子1(两个类型之间的映射)
1 Mapper.CreateMap<AddressDto, Address>(); 2 AddressDto dto = new AddressDto 3 { 4 Country = "China", 5 City = "ShangHai", 6 Street = "JinZhong Street" 7 }; 8 Address address = Mapper.Map<AddressDto,Address>(Dto);
栗子2(两个映射的对象有部分字段名称不一样)
AddressDto到Address的映射,AddressDto的字段CountryName要对应Address的字段Country:
1 Mapper.CreateMap<AddressDto, Address>(). ForMember(d => d.Country, opt => opt.MapFrom(s => s.CountryName));
栗子3(列表类型之间的映射)
源类型List<Address>,目标类型List<AddressDto>:
AutoMapper.Mapper.CreateMap< Address, AddressDto >(); var addressDtoList = AutoMapper.Mapper.Map<List< Address >, List< AddressDto >>( addressList);
栗子4(映射在增改查中的应用)
1 public class ProductBll 2 3 { 4 Public IProductRepository productRepository{ set; get; } 5 public ProductDTO CreateProduct(ProductDTO productDTO) 6 { 7 Mapper.CreateMap<ProductDTO, Product>(); 8 Product product = Mapper.Map<ProductDTO, Product>(productDTO); 9 productRepository.AddProduct(product); 10 return productDTO; 11 } 12 13 public List<ProductDTO> GetProduct() 14 { 15 Mapper.CreateMap<Product, ProductDTO>(); 16 List<ProductDTO> arr = new List<ProductDTO>(); 17 productRepository.GetProduct().ForEach(i => 18 { 19 arr.Add(Mapper.Map<Product, ProductDTO>(i)); 20 }); 21 return arr; 22 } 23 24 public ProductDTO ModifyProduct(ProductDTO productDTO) 25 { 26 Mapper.CreateMap<ProductDTO, Product>(); 27 Product product = Mapper.Map<ProductDTO, Product>(productDTO); 28 productRepository.ModifyProduct(product); 29 return productDTO; 30 } 31 }
三、让AutoMapper使用变得简单
吃过上面的栗子,你觉得怎么样呢?如果想继续吃,那就去查看AutoMapper的具体API文档吧!倘若在项目中真正要用的时候,我觉得还是应该对AutoMapper的方法进行一些整理,最好能够封装一下,这里我通过扩展方法的形式将其封装为AutoMapperHelper,这样以后使用AutoMapper就变的SO EASY了~
1 using System.Collections; 2 using System.Collections.Generic; 3 using System.Data; 4 using AutoMapper; 5 namespace Infrastructure.Utility 6 7 { 8 /// <summary> 9 /// AutoMapper扩展帮助类 10 /// </summary> 11 public static class AutoMapperHelper 12 { 13 /// <summary> 14 /// 类型映射 15 /// </summary> 16 public static T MapTo<T>(this object obj) 17 { 18 if (obj == null) return default(T); 19 Mapper.CreateMap(obj.GetType(), typeof(T)); 20 return Mapper.Map<T>(obj); 21 } 22 /// <summary> 23 /// 集合列表类型映射 24 /// </summary> 25 public static List<TDestination> MapToList<TDestination>(this IEnumerable source) 26 { 27 foreach (var first in source) 28 { 29 var type = first.GetType(); 30 Mapper.CreateMap(type, typeof(TDestination)); 31 break; 32 } 33 return Mapper.Map<List<TDestination>>(source); 34 } 35 /// <summary> 36 /// 集合列表类型映射 37 /// </summary> 38 public static List<TDestination> MapToList<TSource, TDestination>(this IEnumerable<TSource> source) 39 { 40 //IEnumerable<T> 类型需要创建元素的映射 41 Mapper.CreateMap<TSource, TDestination>(); 42 return Mapper.Map<List<TDestination>>(source); 43 } 44 /// <summary> 45 /// 类型映射 46 /// </summary> 47 public static TDestination MapTo<TSource, TDestination>(this TSource source, TDestination destination) 48 where TSource : class 49 where TDestination : class 50 { 51 if (source == null) return destination; 52 Mapper.CreateMap<TSource, TDestination>(); 53 return Mapper.Map(source, destination); 54 } 55 /// <summary> 56 /// DataReader映射 57 /// </summary> 58 public static IEnumerable<T> DataReaderMapTo<T>(this IDataReader reader) 59 { 60 Mapper.Reset(); 61 Mapper.CreateMap<IDataReader, IEnumerable<T>>(); 62 return Mapper.Map<IDataReader, IEnumerable<T>>(reader); 63 } 64 } 65 }
你可以像下面的栗子这样使用:
//对象映射 ShipInfoModel shipInfoModel = ShipInfo.MapTo<ShipInfoModel>(); //列表映射 List< ShipInfoModel > shipInfoModellist = ShipInfoList.MapToList<ShipInfoModel>();
小结
在项目中多使用DTO实现表现层与领域Model的解耦,用AutoMapper来实现DTO与领域Model的相互转换,让AutoMapper在你的项目里飞一会儿