zoukankan      html  css  js  c++  java
  • 初识AutoMapper

    在开始本篇文章之前,先来思考一个问题:一个项目分多层架构,如显示层、业务逻辑层、服务层、数据访问层。层与层访问需要数据载体,也就是类。如果多层通用一个类,一则会暴露出每层的字段,二者会使类字段很多,而且会出现很多冗余字段,这种方式是不可取的;如果每层都使用不同的类,则层与层调用时,一个字段一个字段的赋值又会很麻烦。针对第二种情况,可以使用AutoMapper来帮助我们实现类字段的赋值及转换。

    AutoMapper是一个对象映射器,它可以将一个一种类型的对象转换为另一种类型的对象。AutoMapper提供了映射规则及操作方法,使我们不用过多配置就可以映射两个类。

    安装AutoMapper

    通过Nuget安装AutoMapper,本次使用版本为6.2.2。

    AutoMapper配置

    初始化

    先创建两个类用于映射:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class ProductEntity
    {
        public string Name { getset; }
        public decimal Amount { getset; }
    }
     
    public class ProductDTO
    {
        public string Name { getset; }
        public decimal Amount { getset; }
    }

    Automapper可以使用静态类和实例方法来创建映射,下面分别使用这两种方式来实现 ProductEntity -> ProductDTO的映射。

    • 使用静态方式
    1
    2
    Mapper.Initialize(cfg => cfg.CreateMap<ProductEntity, ProductDTO>());
    var productDTO = Mapper.Map<ProductDTO>(productEntity);
    • 使用实例方法
    1
    2
    3
    MapperConfiguration configuration = new MapperConfiguration(cfg => cfg.CreateMap<ProductEntity, ProductDTO>());
    var mapper = configuration.CreateMapper();
    var productDTO = mapper.Map<ProductDTO>(productEntity);

    完整的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    [TestMethod]
    public void TestInitialization()
    {
        var productEntity = new ProductEntity()
        {
            Name = "Product" + DateTime.Now.Ticks,
            Amount = 10
        };
     
        Mapper.Initialize(cfg => cfg.CreateMap<ProductEntity, ProductDTO>());
        var productDTO = Mapper.Map<ProductDTO>(productEntity);
     
        Assert.IsNotNull(productDTO);
        Assert.IsNotNull(productDTO.Name);
        Assert.IsTrue(productDTO.Amount > 0);
    }

    Profiles设置

    除了使用以上两总方式类配置映射关系,也可以使用Profie配置来实现映射关系。

    创建自定义的Profile需要继承Profile类:

    1
    2
    3
    4
    5
    6
    7
    8
    public class MyProfile : Profile
    {
        public MyProfile()
        {
            CreateMap<ProductEntity, ProductDTO>();
            // Other mapping configurations
        }
    } 

    完成例子:

    除了使用AddProfile,也可以使用AddProfiles添加多个配置;同样,可以同时使用Mapper和Profile,也可以添加多个配置:

    扁平化映射

    AutoMapper先映射名字一致的字段,如果没有,则会尝试使用以下规则来映射:

    • 目标中字段去掉前缀“Get”后的部分
    • 分割目标字段(根据Pascal命名方式)为单个单词

    先创建用到的映射类:

    AutoMapper会自动实现Product.Supplier.Name -> ProductDTO.SupplierName, Product.GetTotal -> ProductDTO.Total的映射。

    集合验证

    AutoMapper除了可以映射单个对象外,也可以映射集合对象。AutoMapper源集合类型支持以下几种:

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

    简单类型映射:

    复杂对象映射:

    投影及条件映射

    投影(指定字段)

    除了以上使用的自动映射规则,AutoMapper还可以指定映射方式。下面使用ForMemeber指定字段的映射,将一个时间值拆分映射到日期、时、分:

    条件映射

     有些情况下,我们会考虑添加映射条件,比如,某个值不符合条件时,不允许映射。针对这种情况可以使用ForMember中的Condition:

    如果要映射的类符合一定的规则,而且有很多,针对每个类都创建一个CreaterMapper会很麻烦。可以使用AddConditionalObjectMapper指定对象映射规则,这样就不用每个映射关系都添加一个CreateMapper。另外,也可以使用AddMemberConfiguration指定字段的映射规则,比如字段的前后缀:

    需要注意的一点是,添加了以上配置,如果目标对象中有字段没有映射到,则会抛出异常。

    值转换

    如果配置了值转换,AutoMapper会将修改转换后的值以符合配置的规则。比如,配置目标对象中的值添加符号“@@”:

    空值替换

    如果要映射的值为Null,则可以使用NullSubstitute指定Null值的替换值:

    配置验证及设置

    配置了映射,但是如何确定是否映射成功或者是否有字段没有映射呢?可以添加Mapper.AssertConfigurationIsValid();来验证是否映射成功。默认情况下,目标对象中的字段都被映射到后,AssertConfigurationIsValid才会返回True。也就是说,源对象必须包含所有目标对象,这样在大多数情况下不是我们想要的,我们可以使用下面的方法来指定验证规则:

    •  指定单个字段不验证
    •  指定整个Map验证规则

    设置转换前后行为

    有的时候你可能会在创建映射前后对数据做一些处理,AutoMapper就提供了这种方式:

    反向映射

    从6.1.0开始,AutoMapper通过调用Reverse可以实现反向映射。反向映射根据初始化时创建的正向映射规则来做反向映射:

    如果反向映射中不想使用原先的映射规则,也可以取消掉:

    自定义转换器

    有些情况下目标字段类型和源字段类型不一致,可以通过类型转换器实现映射,类型转换器有三种实现方式:

    下面通过一个例子来演示下以上三种类型转换器的使用方式:

    自定义解析器

    使用AutoMapper的自带解析规则,我们可以很方便的实现对象的映射。比如:源/目标字段名称一致,“Get/get + 源字段“与"目标字段"一致等。除了这些简单的映射,还可以使用ForMember指定字段映射。但是,某些情况下,解析规则会很复杂,使用自带的解析规则无法实现。这时可以自定义解析规则,可以通过以下三种方式使用自定义的解析器:

    1
    2
    3
    ResolveUsing<TValueResolver>
    ResolveUsing(typeof(CustomValueResolver))
    ResolveUsing(aValueResolverInstance)

    下面通过一个例子来演示如何使用自定义解析器:

    AutoMapper封装

    AutoMapper功能很强大,自定义配置支持也非常好,但是真正项目中使用时却很少用到这么多功能,而且一般都会对AutoMapper进一步封装使用。一方面使用起来方面,另外一方面也可以使代码统一。下面的只是做一个简单的封装,还需要结合实际项目使用:

    总结

    本篇文章列举了AutoMapper的基本使用方式,更多的使用可以参考官方文档:http://automapper.readthedocs.io/en/latest/index.html

  • 相关阅读:
    面向对象
    原型链
    HTTP协议
    java连接数据库(jdbc)调用配置文件
    MySQL-学习笔记
    JAVA-集合框架
    JAVA-多线程
    java中的try-catch-finally异常处理(学习笔记)
    ADO.NET增、删、改、查
    C#资源管理器
  • 原文地址:https://www.cnblogs.com/tsql/p/8743058.html
Copyright © 2011-2022 走看看