AutoMapper 是一个基于命名约定的对象->对象映射工具。
  只要2个对象的属性具有相同名字(或者符合它规定的命名约定),AutoMapper就可以替我们自动在2个对象间进行属性值的映射。如果有不符合约定的属性,或者需要自定义映射行为,就需要我们事先告诉AutoMapper,所以在使用 Map(src,dest)进行映射之前,必须使用 CreateMap() 进行配置。

Mapper.CreateMap<Product, ProductDto>(); // 配置
Product entity = Reop.FindProduct(id); // 从数据库中取得实体
Assert.AreEqual("挖掘机", entity.ProductName);
ProductDto productDto = Mapper.Map(entity); // 使用AutoMapper自动映射
Assert.AreEqual("挖掘机", productDto.ProductName);

AutoMapper就是这样一个只有2个常用函数的简单方便的工具。不过在实际使用时还是有一些细节需要注意,下面将把比较重要的罗列出来。PS:项目的ORM框架是NHibernate。

1. 在程序启动时执行所有的AutoMapper配置,并且把映射代码放置到一起

下面是一个典型的AutoMapper全局配置代码,里面的一些细节会在后面逐一解释。

 1 public class DtoMapping
 2 {
 3     private readonly IContractReviewMainAppServices IContractReviewMainAppServices;
 4     private readonly IDictionaryAppService IDictionaryAppService;
 5     private readonly IProductAppService IProductAppService;
 6     public DtoMapping(IContractReviewMainAppServices IContractReviewMainAppServices,
 7           IDictionaryAppService IDictionaryAppService, IProductAppService IProductAppService)
 8     {
 9         this.IContractReviewMainAppServices = IContractReviewMainAppServices;
10         this.IDictionaryAppService = IDictionaryAppService;
11         this.IProductAppService = IProductAppService;
12     }
13 
14     public void InitMapping()
15     {
16         #region 合同购买设备信息
17         Mapper.CreateMap<ContractReviewProduct, ContractReviewProductDto>();
18         Mapper.CreateMap<ContractReviewProductDto, ContractReviewProduct>() // DTO 向 Entity 赋值
19               .ForMember(entity => entity.ContractReviewMain, opt => LoadEntity(opt,
20                                                                                 dto => dto.ContractReviewMainId,
21                                                                                 IContractReviewMainAppServices.Get))
22               .ForMember(entity => entity.DeviceCategory, opt => LoadEntity(opt,
23                                                                             dto => dto.DeviceCategoryId,
24                                                                             IDictionaryAppService.FindDicItem))
25               .ForMember(entity => entity.DeviceName, opt => LoadEntity(opt,
26                                                                         dto => dto.DeviceNameId,
27                                                                         IProductAppService.FindProduct))
28               .ForMember(entity => entity.ProductModel, opt => LoadEntity(opt,
29                                                                           dto => dto.ProductModelId,
30                                                                           IProductAppService.FindProduct))
31               .ForMember(entity => entity.Unit, opt => LoadEntity(opt,
32                                                                   dto => dto.UnitId,
33                                                                   IDictionaryAppService.FindDicItem))
34               .ForMember(entity => entity.Creator, opt => opt.Ignore()); // DTO 里面没有的属性直接Ignore
35         #endregion 合同购买设备信息
36 
37         #region 字典配置
38         Mapper.CreateMap<DicCategory, DicCategoryDto>();
39         Mapper.CreateMap<DicCategoryDto, DicCategory>();
40         Mapper.CreateMap<DicItem, DicItemDto>();
41         Mapper.CreateMap<DicItemDto, DicItem>()
42               .ForMember(entity => entity.Category, opt => LoadEntity(opt,
43                                                                       dto => dto.CategoryId,
44                                                                       IDictionaryAppService.FindDicCategory));
45         #endregion 字典配置
46 
47         // 对于所有的 DTO 到 Entity 的映射,都忽略 Id 和 Version 属性
48         IgnoreDtoIdAndVersionPropertyToEntity();
49 
50         // 验证配置
51         Mapper.AssertConfigurationIsValid();
52     }
53 
54     /// <summary>
55     /// 加载实体对象。
56     /// <remarks>Id是null的会被忽略;Id是string.Empty的将被赋值为null;Id是GUID的将从数据库中加载并赋值。</remarks> 
57     /// </summary>
58     /// <typeparam name="TSource"></typeparam>
59     /// <typeparam name="TMember"></typeparam>
60     /// <param name="opt"></param>
61     /// <param name="getId"></param>
62     /// <param name="doLoad"></param>
63     private void LoadEntity<TSource, TMember>(IMemberConfigurationExpression<TSource> opt,
64         Func<TSource, string> getId, Func<string, TMember> doLoad) where TMember : class
65     {
66         opt.Condition(src => (getId(src) != null));
67         opt.MapFrom(src => getId(src) == string.Empty ? null : doLoad(getId(src)));
68     }
69 
70     /// <summary>
71     /// 对于所有的 DTO 到 Entity 的映射,都忽略 Id 和 Version 属性
72     /// <remarks>当从DTO向Entity赋值时,要保持从数据库中加载过来的Entity的Id和Version属性不变!</remarks>
73     /// </summary>
74     private void IgnoreDtoIdAndVersionPropertyToEntity()
75     {
76         PropertyInfo idProperty = typeof(Entity).GetProperty("Id");
77         PropertyInfo versionProperty = typeof(Entity).GetProperty("Version");
78         foreach (TypeMap map in Mapper.GetAllTypeMaps())
79         {
80             if (typeof(Dto).IsAssignableFrom(map.SourceType)
81                 && typeof(Entity).IsAssignableFrom(map.DestinationType))
82             {
83                 map.FindOrCreatePropertyMapFor(new PropertyAccessor(idProperty)).Ignore();
84                 map.FindOrCreatePropertyMapFor(new PropertyAccessor(versionProperty)).Ignore();
85             }
86         }
87     }
88 }
DTO 与 Entity 之间的 AutoMapper全局配置代码

相关文章:

  • 2021-11-23
  • 2021-12-23
  • 2021-07-05
  • 2022-01-03
  • 2022-01-19
  • 2022-01-17
  • 2021-04-29
猜你喜欢
  • 2021-11-23
  • 2022-01-30
  • 2021-06-17
  • 2021-12-17
相关资源
相似解决方案