AutoMapper的匹配

1,智能匹配

     AutoMapper能够自动识别和匹配大部分对象属性:

    • 如果源类和目标类的属性名称相同,直接匹配,不区分大小写
    • 目标类型的CustomerName可以匹配源类型的Customer.Name
    • 目标类型的Total可以匹配源类型的GetTotal()方法

2,自定义匹配

    Mapper.CreateMap<CalendarEvent, CalendarEventForm>()                                                    //属性匹配,匹配源类中WorkEvent.Date到EventDate

    .ForMember(dest => dest.EventDate, opt => opt.MapFrom(src => src.WorkEvent.Date))

    .ForMember(dest => dest.SomeValue, opt => opt.Ignore())                                                 //忽略目标类中的属性

    .ForMember(dest => dest.TotalAmount, opt => opt.MapFrom(src => src.TotalAmount ?? 0))  //复杂的匹配

    .ForMember(dest => dest.OrderDate, opt => opt.UserValue<DateTime>(DateTime.Now));      //固定值匹配

直接匹配

源类的属性名称和目标类的属性名称相同(不区分大小写),直接匹配,Mapper.CreateMap<source,dest>();无需做其他处理,此处不再细述

Flattening

将一个复杂的对象模型拉伸为,或者扁平化为一个简单的对象模型,如下面这个复杂的对象模型:

  1. public class Order
  2. {
  3. private readonly IList<OrderLineItem> _orderLineItems = new List<OrderLineItem>();
  4.  
  5. public Customer Customer { get; set; }
  6.  
  7. public OrderLineItem[] GetOrderLineItems()
  8. {
  9. return _orderLineItems.ToArray();
  10. }
  11.  
  12. public void AddOrderLineItem(Product product, int quantity)
  13. {
  14. _orderLineItems.Add(new OrderLineItem(product, quantity));
  15. }
  16.  
  17. public decimal GetTotal()
  18. {
  19. return _orderLineItems.Sum(li => li.GetTotal());
  20. }
  21. }
  22.  
  23. public class Product
  24. {
  25. public decimal Price { get; set; }
  26. public string Name { get; set; }
  27. }
  28.  
  29. public class OrderLineItem
  30. {
  31. public OrderLineItem(Product product, int quantity)
  32. {
  33. Product = product;
  34. Quantity = quantity;
  35. }
  36.  
  37. public Product Product { get; private set; }
  38. public int Quantity { get; private set; }
  39.  
  40. public decimal GetTotal()
  41. {
  42. return Quantity * Product.Price;
  43. }
  44. }
  45.  
  46. public class Customer
  47. {
  48. public string Name { get; set; }
  49. }

我们要把这一复杂的对象简化为OrderDTO,只包含某一场景所需要的数据:

  1. public class OrderDto
  2. {
  3. public string CustomerName { get; set; }
  4. public decimal Total { get; set; }
  5. }

运用AutoMapper转换:

  1. public void Example()
  2. {
  3. // Complex model
  4. var customer = new Customer
  5. {
  6. Name = "George Costanza"
  7. };
  8. var order = new Order
  9. {
  10. Customer = customer
  11. };
  12. var bosco = new Product
  13. {
  14. Name = "Bosco",
  15. Price = 4.99m
  16. };
  17. order.AddOrderLineItem(bosco, );
  18.  
  19. // Configure AutoMapper
  20. var config = new MapperConfiguration(cfg => cfg.CreateMap<Order, OrderDto>());
  21.  
  22. // Perform mapping
  23. var mapper = config.CreateMapper();
  24. OrderDto dto = mapper.Map<Order, OrderDto>(order);
  25.  
  26. dto.CustomerName.ShouldEqual("George Costanza");
  27. dto.Total.ShouldEqual(74.85m);
  28. }

可以看到只要设置下Order和OrderDto之间的类型映射就可以了,我们看OrderDto中的CustomerName和Total属性在领域模型Order中并没有与之相对性,AutoMapper在做解析的时候会按照PascalCase(帕斯卡命名法),CustomerName其实是由Customer+Name 得来的,是AutoMapper的一种映射规则;而Total是因为在Order中有GetTotal()方法,AutoMapper会解析“Get”之后的单词,所以会与Total对应。在编写代码过程中可以运用这种规则来定义名称实现自动转换。

Projection

Projection可以理解为与Flattening相反,Projection是将源对象映射到一个不完全与源对象匹配的目标对象,需要制定自定义成员,如下面的源对象:

  1. public class CalendarEvent
  2. {
  3. public DateTime EventDate { get; set; }
  4. public string Title { get; set; }
  5. }

目标对象:

  1. public class CalendarEventForm
  2. {
  3. public DateTime EventDate { get; set; }
  4. public int EventHour { get; set; }
  5. public int EventMinute { get; set; }
  6. public string Title { get; set; }
  7. }

AutoMapper配置转换代码:

  1. public void Example()
  2. {
  3. // Model
  4. var calendarEvent = new CalendarEvent
  5. {
  6. EventDate = new DateTime(, , , , , ),
  7. Title = "Company Holiday Party"
  8. };
  9.  
  10. var config = new MapperConfiguration(cfg =>
  11. {
  12. // Configure AutoMapper
  13. cfg.CreateMap<CalendarEvent, CalendarEventForm>()
  14. .ForMember(dest => dest.EventDate, opt => opt.MapFrom(src => src.EventDate.Date))
  15. .ForMember(dest => dest.EventHour, opt => opt.MapFrom(src => src.EventDate.Hour))
  16. .ForMember(dest => dest.EventMinute, opt => opt.MapFrom(src => src.EventDate.Minute));
  17. });
  18.  
  19. // Perform mapping
  20. var mapper = config.CreateMapper();
  21. CalendarEventForm form = mapper.Map<CalendarEvent, CalendarEventForm>(calendarEvent);
  22.  
  23. form.EventDate.ShouldEqual(new DateTime(, , ));
  24. form.EventHour.ShouldEqual();
  25. form.EventMinute.ShouldEqual();
  26. form.Title.ShouldEqual("Company Holiday Party");
  27. }

Configuration Validation

在进行对象映射的时候,有可能会出现属性名称或者自定义匹配规则不正确而又没有发现的情况,在程序执行时就报错,因此,AutoMapper提供的AssertConfigurationIsValid()方法来验证结构映射是否正确。

config.AssertConfigurationIsValid();如果映射错误,会报“AutoMapperConfigurationException”异常错误,就可以进行调试修改了

Lists and Array

AutoMapper支持的源集合类型包括:

  • IEnumerable
  • IEnumerable<T>
  • ICollection
  • ICollection<T>
  • IList
  • IList<T>
  • List<T>
  • Arrays

有一种情况是,在使用集合类型类型的时候,类型之间存在继承关系,例如下面我们需要转换的类型:

  1. //源对象
  2. public class ParentSource
  3. {
  4. public int Value1 { get; set; }
  5. }
  6.  
  7. public class ChildSource : ParentSource
  8. {
  9. public int Value2 { get; set; }
  10. }
  11.  
  12. //目标对象
  13. public class ParentDestination
  14. {
  15. public int Value1 { get; set; }
  16. }
  17.  
  18. public class ChildDestination : ParentDestination
  19. {
  20. public int Value2 { get; set; }
  21. }

AutoMapper需要孩子映射的显式配置,AutoMapper配置转换代码:

  1. var config = new MapperConfiguration(cfg =>
  2. {
  3. cfg.CreateMap<ParentSource, ParentDestination>()
  4. .Include<ChildSource, ChildDestination>();
  5. cfg.CreateMap<ChildSource, ChildDestination>();
  6. });
  7.  
  8. var sources = new[]
  9. {
  10. new ParentSource(),
  11. new ChildSource(),
  12. new ParentSource()
  13. };
  14.  
  15. var destinations = config.CreateMapper().Map<ParentSource[], ParentDestination[]>(sources);
  16.  
  17. destinations[].ShouldBeType<ParentDestination>();
  18. destinations[].ShouldBeType<ChildDestination>();
  19. destinations[].ShouldBeType<ParentDestination>();

注意在Initialize初始化CreateMap进行类型映射配置的时候有个Include泛型方法,签名为:“Include this configuration in derived types' maps”,大致意思为包含派生类型中配置,ChildSource是ParentSource的派生类,ChildDestination是ParentDestination的派生类,cfg.CreateMap<ParentSource, ParentDestination>().Include<ChildSource, ChildDestination>(); 这段代码是说明ParentSource和ChildSource之间存在的关系,并且要要显示的配置。

Nested mappings

嵌套对象映射,例如下面的对象:

  1.        public class OuterSource
  2. {
  3. public int Value { get; set; }
  4. public InnerSource Inner { get; set; }
  5. }
  6.  
  7. public class InnerSource
  8. {
  9. public int OtherValue { get; set; }
  10. }
  11.  
  12. //目标对象
  13. public class OuterDest
  14. {
  15. public int Value { get; set; }
  16. public InnerDest Inner { get; set; }
  17. }
  18.  
  19. public class InnerDest
  20. {
  21. public int OtherValue { get; set; }
  22. }

AutoMapper配置转换代码:

  1. var config = new MapperConfiguration(cfg =>
  2. {
  3. cfg.CreateMap<OuterSource, OuterDest>();
  4. cfg.CreateMap<InnerSource, InnerDest>();
  5. });
  6. config.AssertConfigurationIsValid();
  7.  
  8. var source = new OuterSource
  9. {
  10. Value = ,
  11. Inner = new InnerSource {OtherValue = }
  12. };
  13.  
  14. var dest = config.CreateMapper().Map<OuterSource, OuterDest>(source);
  15.  
  16. dest.Value.ShouldEqual();
  17. dest.Inner.ShouldNotBeNull();
  18. dest.Inner.OtherValue.ShouldEqual();

对于嵌套映射,只要指定下类型映射关系和嵌套类型映射关系就可以了,也就是这段代码:“Mapper.CreateMap<InnerSource, InnerDest>();” 其实我们在验证类型映射的时候加上Mapper.AssertConfigurationIsValid(); 这段代码看是不是抛出“AutoMapperMappingException”异常来判断类型映射是否正确。

参考资料

关于AutoMapper,陆续更新中...

AutoMapper的介绍与使用(二)的更多相关文章

  1. AutoMapper.RegExtension 介绍

    AutoMapper.RegExtension 为一个特小特小特小的用来根据约定自动调用AutoMapper中的方法配置映射的扩展库.你可以引入该库也可以将源码中核心部分的代码文件夹整个拷贝至项目中. ...

  2. 从Client应用场景介绍IdentityServer4(二)

    原文:从Client应用场景介绍IdentityServer4(二) 本节介绍Client的ClientCredentials客户端模式,先看下画的草图: 一.在Server上添加动态新增Client ...

  3. c语言学习之基础知识点介绍(十二):结构体的介绍

    一.结构体的介绍 /* 语法: struct 结构体名{ 成员列表; }; 切记切记有分号! 说明:成员列表就是指你要保存哪些类型的数据. 注意:上面的语法只是定义一个新的类型,而这个类型叫做结构体类 ...

  4. Spring 使用介绍(十二)—— Spring Task

    一.概述 1.jdk的线程池和任务调用器分别由ExecutorService.ScheduledExecutorService定义,继承关系如下: ThreadPoolExecutor:Executo ...

  5. (转)OpenStack —— 原理架构介绍(一、二)

    原文:http://blog.51cto.com/wzlinux/1961337 http://blog.51cto.com/wzlinux/category18.html-------------O ...

  6. AutoMapper的介绍与使用(一)

    软件环境 vs2015 asp.net mvc 5 .NET Framework 4.5.2 AutoMapper 5.2.0.0 AutoMapper安装 新建asp.net mvc 项目 Auto ...

  7. SaaS系列介绍之十二: SaaS产品的研发模式

    1 产品研发模式慨述 产品研发模式是企业战略的重点.产品研发路线决定了一系列的管理手段和团队建设问题.也是企业的整理策略和经营思路.产品研发模式贯穿着整个产品的生命周期,从市场调研.立项.需求分析.慨 ...

  8. 微设计(www.weidesigner.com)介绍系列文章(二)

    微设计(www.weidesigner.com)是一个专门针对微信公众账号提供营销推广服务而打造的第三方平台. 2.1 怎样注冊微信公众号? 登录mp.weixin.qq.com,点击注冊填写相关信息 ...

  9. Cordova各个插件使用介绍系列(二)—$cordovaBarcodeScanner扫描二维码与生成二维码

    详情链接地址:http://www.ncloud.hk/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/cordova-2-cordovabarcodescanner/ 这是 ...

随机推荐

  1. MAC Osx PHP安装指导

    php.ini的位置 Mac OS X中没有默认的php.ini文件,但是有对应的模版文件php.ini.default,位于/private/etc/php.ini.default 或者说 /etc ...

  2. AFNetworking 3.0 源码解读 总结(干货)(上)

    养成记笔记的习惯,对于一个软件工程师来说,我觉得很重要.记得在知乎上看到过一个问题,说是人类最大的缺点是什么?我个人觉得记忆算是一个缺点.它就像时间一样,会自己消散. 前言 终于写完了 AFNetwo ...

  3. 声音分贝的概念,dBSPL.dBm,dBu,dBV,dBFS

    需要做个音频的PPM表,看着一堆的音频术语真是懵了,苦苦在网上扒了几天的文档,终于有了点收获,下面关于声音的分贝做个总结. 分贝 Decibel 分贝(dB)是一个对数单位(logarithmic u ...

  4. wordpress优化之结合prism.js为编辑器自定义按钮转化代码

    原文链接 http://ymblog.net/2016/07/24/wordpress-prism/ 继昨天花了一天一夜的时间匆匆写了主题Jiameil3.0之后,心中一直在想着优化加速,体验更好,插 ...

  5. UWP简单示例(三):快速开发2D游戏引擎

    准备 IDE:VisualStudio 2015 Language:VB.NET/C# 图形API:Win2D MSDN教程:UWP游戏开发 游戏开发涉及哪些技术? 游戏开发是一门复杂的艺术,编码方面 ...

  6. ASP.NET MVC5----常见的数据注解和验证

    只要一直走,慢点又何妨. 在使用MVC模式进行开发时,数据注解是经常使用的(模型之上操作),下面是我看书整理的一些常见的用法. 什么是验证,数据注解 验证 从全局来看,发现逻辑仅是整个验证的很小的一部 ...

  7. 图解CSS3制作圆环形进度条的实例教程

    圆环形进度条制作的基本思想还是画出基本的弧线图形,然后CSS3中我们可以控制其旋转来串联基本图形,制造出部分消失的效果,下面就来带大家学习图解CSS3制作圆环形进度条的实例教程 首先,当有人说你能不能 ...

  8. JavaScript 正则表达式语法

    定义 JavaScript定义正则表达式有两种方法. 1.RegExp构造函数 var pattern = new RegExp("[bc]at","i"); ...

  9. Apache Cordova开发Android应用程序——番外篇

    很多天之前就安装了visual studio community 2015,今天闲着么事想试一下Apache Cordova,用它来开发跨平台App.在这之前需要配置N多东西,这里找到了一篇MS官方文 ...

  10. Android Studio切换为eclipse的快捷键之后还是有区别的部分快捷键

    Android Studio Eclipse 把代码提示换成了Class Name Completion, 快捷键是Ctrl+Alt+Space(空格键). 代码提示快捷键Alt+/,         ...