AutoMapper的介绍与使用(二)

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, 15);

                // 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(2008, 12, 15, 20, 30, 0),
                        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(2008, 12, 15));
                form.EventHour.ShouldEqual(20);
                form.EventMinute.ShouldEqual(30);
                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[0].ShouldBeType<ParentDestination>();
                destinations[1].ShouldBeType<ChildDestination>();
                destinations[2].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 = 5,
                        Inner = new InnerSource {OtherValue = 15}
                    };

                var dest = config.CreateMapper().Map<OuterSource, OuterDest>(source);

                dest.Value.ShouldEqual(5);
                dest.Inner.ShouldNotBeNull();
                dest.Inner.OtherValue.ShouldEqual(15);

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

参考资料

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

时间: 2024-08-04 19:30:36

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

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

一.概述 1.jdk的线程池和任务调用器分别由ExecutorService.ScheduledExecutorService定义,继承关系如下: / ThreadPoolExecutor:ExecutorService的实现类,其构造函数提供了灵活的参数配置,可构造多种类型的线程池,详细可参考JAVA进阶----ThreadPoolExecutor机制 ScheduledThreadPoolExecutor:ScheduledExecutorService的实现类,用于任务调动 2.sprin

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

原文:http://blog.51cto.com/wzlinux/1961337 http://blog.51cto.com/wzlinux/category18.html-------------OpenStack -- 原理架构介绍(一~九) 一.OpenStack 简介 Openstack是一个控制着大量计算能力.存储.乃至于整个数据中心网络资源的云操作系统,通过Dashboard这个Web界面,让管理员可以控制.赋予他们的用户去提供资源的权限(即:能够通过Dashboard控制整个Ope

Vue的介绍以及说明(二)

一,循环指令代码展示 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>循环指令</title> <script src="js/vue.js"></script> </head> <body> <div id="app&q

Linux shell脚本基础学习详细介绍(完整版)二

详细介绍Linux shell脚本基础学习(五) Linux shell脚本基础前面我们在介绍Linux shell脚本的控制流程时,还有一部分内容没讲就是有关here document的内容这里继续. Linux shell脚本基础已经被分成好几个部分了,这里对控制流程的内容也就马上讲完了,这是最后一部分关于here document,这里举例稍微有点复杂,我们慢慢来分析这个复杂Linux shell脚本. 6. Here documents 当要将几行文字传递给一个命令时,here docu

AutoMapper的介绍与使用(一)

软件环境 vs2015 asp.net mvc 5 .NET Framework 4.5.2 AutoMapper 5.2.0.0 AutoMapper安装 新建asp.net mvc 项目 AutoMapperExample,此处应该都会用vs新建mvc项目了,不再讲解如何创建 , 点击 工具→NuGetB包管理器→管理解决方案的NuGet程序包,在弹出的界面中,选中 "浏览",输入autoMapper,回车搜索,在搜索出的程序包中,选中第一个,然后安装 输出如下图所示,则表示安装A

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

详情链接地址:http://www.ncloud.hk/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/cordova-2-cordovabarcodescanner/ 这是一个用来扫描二维码的cordova插件,在做项目的时候想实现类似于微信的扫一扫功能,就想到了cordova的$cordovaBarcodeScanner插件,用很少量的代码就可以实现了,下面来看一下具体的实现步骤: 一.扫描二维码: 1.首先需要有一个简单的项目,然后在命令行输入添加插件的命令: c

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

1 产品研发模式慨述 产品研发模式是企业战略的重点.产品研发路线决定了一系列的管理手段和团队建设问题.也是企业的整理策略和经营思路.产品研发模式贯穿着整个产品的生命周期,从市场调研.立项.需求分析.慨要设计.详细设计.开发.测试.发布.维护等传统软件工程思想到现在流行的IPD,以市场为导向的商业模式都无不在改变传统的研发模式.以服务体验为核心的新思想更是SaaS模式的本质.我们不是以产品研发而开发,我们一定是为市场价值开发而研发. 2 几种主流的产品开发模式 l 以项目管理的职能式开发 这是企业

Android官方架构组件介绍之LiveData(二)

LiveData LiveData是一个用于持有数据并支持数据可被监听(观察).和传统的观察者模式中的被观察者不一样,LiveData是一个生命周期感知组件,因此观察者可以指定某一个LifeCycle给LiveData,并对数据进行监听. 如果观察者指定LifeCycle处于Started或者RESUMED状态,LiveData会将观察者视为活动状态,并通知其数据的变化. 我们看一段代码: public class LocationLiveData extends LiveData<Locati

Ansible Playbooks 介绍 和 使用 二

目录 handlers playbook 案例 2 handlers vars 变量 setup facts 变量使用 案例 inventory 中定义变量 案例 条件测试 when 语句 案例 handlers 接上一篇文章 Ansible Playbooks 介绍 和 使用 一 继续说明 用于当关注的资源发生变化时采取一定的操作. notify这个 action可用于在每个play的最后被处罚,这样可以避免多次有改变时每次都执行指定的操作,取而代之,尽在所有的变化发生完成后一次性执行指定的操