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

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

        public class Order
{
private readonly IList<OrderLineItem> _orderLineItems = new List<OrderLineItem>(); public Customer Customer { get; set; } public OrderLineItem[] GetOrderLineItems()
{
return _orderLineItems.ToArray();
} public void AddOrderLineItem(Product product, int quantity)
{
_orderLineItems.Add(new OrderLineItem(product, quantity));
} public decimal GetTotal()
{
return _orderLineItems.Sum(li => li.GetTotal());
}
} public class Product
{
public decimal Price { get; set; }
public string Name { get; set; }
} public class OrderLineItem
{
public OrderLineItem(Product product, int quantity)
{
Product = product;
Quantity = quantity;
} public Product Product { get; private set; }
public int Quantity { get; private set; } public decimal GetTotal()
{
return Quantity * Product.Price;
}
} public class Customer
{
public string Name { get; set; }
}

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

        public class OrderDto
{
public string CustomerName { get; set; }
public decimal Total { get; set; }
}

运用AutoMapper转换:

            public void Example()
{
// Complex model
var customer = new Customer
{
Name = "George Costanza"
};
var order = new Order
{
Customer = customer
};
var bosco = new Product
{
Name = "Bosco",
Price = 4.99m
};
order.AddOrderLineItem(bosco, ); // Configure AutoMapper
var config = new MapperConfiguration(cfg => cfg.CreateMap<Order, OrderDto>()); // Perform mapping
var mapper = config.CreateMapper();
OrderDto dto = mapper.Map<Order, OrderDto>(order); dto.CustomerName.ShouldEqual("George Costanza");
dto.Total.ShouldEqual(74.85m);
}

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

Projection

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

        public class CalendarEvent
{
public DateTime EventDate { get; set; }
public string Title { get; set; }
}

目标对象:

        public class CalendarEventForm
{
public DateTime EventDate { get; set; }
public int EventHour { get; set; }
public int EventMinute { get; set; }
public string Title { get; set; }
}

AutoMapper配置转换代码:

            public void Example()
{
// Model
var calendarEvent = new CalendarEvent
{
EventDate = new DateTime(, , , , , ),
Title = "Company Holiday Party"
}; var config = new MapperConfiguration(cfg =>
{
// Configure AutoMapper
cfg.CreateMap<CalendarEvent, CalendarEventForm>()
.ForMember(dest => dest.EventDate, opt => opt.MapFrom(src => src.EventDate.Date))
.ForMember(dest => dest.EventHour, opt => opt.MapFrom(src => src.EventDate.Hour))
.ForMember(dest => dest.EventMinute, opt => opt.MapFrom(src => src.EventDate.Minute));
}); // Perform mapping
var mapper = config.CreateMapper();
CalendarEventForm form = mapper.Map<CalendarEvent, CalendarEventForm>(calendarEvent); form.EventDate.ShouldEqual(new DateTime(, , ));
form.EventHour.ShouldEqual();
form.EventMinute.ShouldEqual();
form.Title.ShouldEqual("Company Holiday Party");
}

Configuration Validation

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

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

Lists and Array

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

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

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

            //源对象
public class ParentSource
{
public int Value1 { get; set; }
} public class ChildSource : ParentSource
{
public int Value2 { get; set; }
} //目标对象
public class ParentDestination
{
public int Value1 { get; set; }
} public class ChildDestination : ParentDestination
{
public int Value2 { get; set; }
}

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

                var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<ParentSource, ParentDestination>()
.Include<ChildSource, ChildDestination>();
cfg.CreateMap<ChildSource, ChildDestination>();
}); var sources = new[]
{
new ParentSource(),
new ChildSource(),
new ParentSource()
}; var destinations = config.CreateMapper().Map<ParentSource[], ParentDestination[]>(sources); destinations[].ShouldBeType<ParentDestination>();
destinations[].ShouldBeType<ChildDestination>();
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

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

       public class OuterSource
{
public int Value { get; set; }
public InnerSource Inner { get; set; }
} public class InnerSource
{
public int OtherValue { get; set; }
} //目标对象
public class OuterDest
{
public int Value { get; set; }
public InnerDest Inner { get; set; }
} public class InnerDest
{
public int OtherValue { get; set; }
}

AutoMapper配置转换代码:

                var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<OuterSource, OuterDest>();
cfg.CreateMap<InnerSource, InnerDest>();
});
config.AssertConfigurationIsValid(); var source = new OuterSource
{
Value = ,
Inner = new InnerSource {OtherValue = }
}; var dest = config.CreateMapper().Map<OuterSource, OuterDest>(source); dest.Value.ShouldEqual();
dest.Inner.ShouldNotBeNull();
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. JDK动态代理

    一.基本概念 1.什么是代理? 在阐述JDK动态代理之前,我们很有必要先来弄明白代理的概念.代理这个词本身并不是计算机专用术语,它是生活中一个常用的概念.这里引用维基百科上的一句话对代理进行定义: A ...

  2. 关于DDD的学习资料汇总

    DDD(Domain-Driven Design)领域驱动设计,第一次看到DDD是在学习ABP时,在其中的介绍中看到的.what,DDD是个什么鬼,我不是小白,是大白,没听过.于是乎,度娘查查查,找到 ...

  3. Android 扫描条形码(Zxing插件)

    使用Android Studio 一.在build.gradle(Module:app)添加代码  下载,调用插件 1 apply plugin: 'com.android.application' ...

  4. iOS app内存分析套路

    iOS app内存分析套路 Xcode下查看app内存使用情况有2中方法: Navigator导航栏中的Debug navigator中的Memory Instruments 一.Debug navi ...

  5. python性能检测工具整理

    python 运行后出现core dump产生core.**文件,可通过gdb来调试 Using GDB with a core dump having found build/python/core ...

  6. PHP5.4~7.1新特性总结

    http://note.youdao.com/noteshare?id=7273b858fc12873ad092979e4ba173a7&sub=WEB334fdcf50b507ad93549 ...

  7. 钉钉开放平台demo调试异常问题解决:hostname in certificate didn't match

    今天研究钉钉的开放平台,结果一个demo整了半天,这帮助系统写的也很难懂.遇到两个问题: 1.首先是执行demo时报unable to find valid certification path to ...

  8. SQL SERVER全面优化-------Expert for SQL Server 诊断系列

    现在很多用户被数据库的慢的问题所困扰,又苦于花钱请一个专业的DBA成本太高.软件维护人员对数据库的了解又不是那么深入,所以导致问题迟迟不能解决,或只能暂时解决不能得到根治.开发人员解决数据问题基本又是 ...

  9. 2000条你应知的WPF小姿势 基础篇<1-7>

    在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师,对C#和WPF有着极深的热情.最为出色的是他维护了两个博客:2,000Things You Should Know ...

  10. 给WinForm窗体添加快捷键 响应回车键、空格键

    1.设置窗体KeyPreview属性为True 2.添加窗体的KeyDown事件 /// <summary> /// 窗体的keydown事件响应 添加快捷键 /// </summa ...