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

  • 相关阅读:
    基于Python的人脸动漫转换
    let 与 var的区别
    【LeetCode】汇总
    【HDU】4632 Palindrome subsequence(回文子串的个数)
    【算法】均匀的生成圆内的随机点
    【LeetCode】725. Split Linked List in Parts
    【LeetCode】445. Add Two Numbers II
    【LeetCode】437. Path Sum III
    【LeetCode】222. Count Complete Tree Nodes
    【LeetCode】124. Binary Tree Maximum Path Sum
  • 原文地址:https://www.cnblogs.com/tsql/p/8743058.html
Copyright © 2011-2022 走看看