【C#】AutoMapper 使用手册

本文基于 AutoMapper 9.0.0

AutoMapper 是一个对象-对象映射器,可以将一个对象映射到另一个对象。

官网地址:http://automapper.org/

官方文档:https://docs.automapper.org/en/latest/

1 入门例子

public class Foo{    public int ID { get; set; }    public string Name { get; set; }}public class FooDto{    public int ID { get; set; }    public string Name { get; set; }}public void Map(){    var config = new MapperConfiguration(cfg => cfg.CreateMap<Foo, FooDto>());    var mapper = config.CreateMapper();    Foo foo = new Foo { ID = 1, Name = "Tom" };    FooDto dto = mapper.Map<FooDto>(foo);}

2 注册

在使用 Map 方法之前,首先要告诉 AutoMapper 什么类可以映射到什么类。

var config = new MapperConfiguration(cfg => cfg.CreateMap<Foo, FooDto>());

每个 AppDomain 只能进行一次配置。这意味着放置配置代码的最佳位置是在应用程序启动中,例如 ASP.NET 应用程序的 Global.asax 文件。

从 9.0 开始 Mapper.Initialize 方法就不可用了。

2.1 Profile

Profile 是组织映射的另一种方式。新建一个类,继承 Profile,并在构造函数中配置映射。

public class EmployeeProfile : Profile{    public EmployeeProfile()    {        CreateMap<Employee, EmployeeDto>();    }}var config = new MapperConfiguration(cfg =>{    cfg.AddProfile<EmployeeProfile>();});

Profile 内部的配置仅适用于 Profile 内部的映射。应用于根配置的配置适用于所有创建的映射。

AutoMapper 也可以在指定的程序集中扫描从 Profile 继承的类,并将其添加到配置中。

var config = new MapperConfiguration(cfg =>{    // 扫描当前程序集    cfg.AddMaps(System.AppDomain.CurrentDomain.GetAssemblies());        // 也可以传程序集名称(dll 名称)    cfg.AddMaps("LibCoreTest");});

3 配置

3.1 命名约定

默认情况下,AutoMapper 基于相同的字段名映射,并且是 不区分大小写 的。

但有时,我们需要处理一些特殊的情况。

  • SourceMemberNamingConvention 表示源类型命名规则

  • DestinationMemberNamingConvention 表示目标类型命名规则

LowerUnderscoreNamingConventionPascalCaseNamingConvention 是 AutoMapper 提供的两个命名规则。前者命名是小写并包含下划线,后者就是帕斯卡命名规则(每个单词的首字母大写)。

我的理解,如果源类型和目标类型分别采用了 蛇形命名法驼峰命名法,那么就需要指定命名规则,使其能正确映射。

public class Foo{    public int Id { get; set; }    public string MyName { get; set; }}public class FooDto{    public int ID { get; set; }    public string My_Name { get; set; }}public void Map(){    var config = new MapperConfiguration(cfg =>    {        cfg.CreateMap<Foo, FooDto>();        cfg.SourceMemberNamingConvention = new PascalCaseNamingConvention();        cfg.DestinationMemberNamingConvention = new LowerUnderscoreNamingConvention();    });    var mapper = config.CreateMapper();    Foo foo = new Foo { Id = 2, MyName = "Tom" };    FooDto dto = mapper.Map<FooDto>(foo);}

3.2 配置可见性

默认情况下,AutoMapper 仅映射 public 成员,但其实它是可以映射到 private 属性的。

var config = new MapperConfiguration(cfg =>{    cfg.ShouldMapProperty = p => p.GetMethod.IsPublic || p.SetMethod.IsPrivate;    cfg.CreateMap<Source, Destination>();});

需要注意的是,这里属性必须添加 private set,省略 set 是不行的。

3.3 全局属性/字段过滤

默认情况下,AutoMapper 尝试映射每个公共属性/字段。以下配置将忽略字段映射。

var config = new MapperConfiguration(cfg =>{cfg.ShouldMapField = fi => false;});

3.4 识别前缀和后缀

var config = new MapperConfiguration(cfg =>{    cfg.RecognizePrefixes("My");    cfg.RecognizePostfixes("My");}

3.5 替换字符

var config = new MapperConfiguration(cfg =>{    cfg.ReplaceMemberName("Ä", "A");});

这功能我们基本上用不上。

4 调用构造函数

有些类,属性的 set 方法是私有的。

public class Commodity{    public string Name { get; set; }    public int Price { get; set; }}public class CommodityDto{    public string Name { get; }    public int Price { get; }    public CommodityDto(string name, int price)    {        Name = name;        Price = price * 2;    }}

AutoMapper 会自动找到相应的构造函数调用。如果在构造函数中对参数做一些改变的话,其改变会反应在映射结果中。如上例,映射后 Price 会乘 2。

禁用构造函数映射:

var config = new MapperConfiguration(cfg => cfg.DisableConstructorMapping());

禁用构造函数映射的话,目标类要有一个无参构造函数。

5 数组和列表映射

数组和列表的映射比较简单,仅需配置元素类型,定义简单类型如下:

public class Source{    public int Value { get; set; }}public class Destination{    public int Value { get; set; }}

映射:

var config = new MapperConfiguration(cfg =>{    cfg.CreateMap<Source, Destination>();});IMapper mapper = config.CreateMapper();var sources = new[]{    new Source { Value = 5 },    new Source { Value = 6 },    new Source { Value = 7 }};IEnumerable<Destination> ienumerableDest = mapper.Map<Source[], IEnumerable<Destination>>(sources);ICollection<Destination> icollectionDest = mapper.Map<Source[], ICollection<Destination>>(sources);IList<Destination> ilistDest = mapper.Map<Source[], IList<Destination>>(sources);List<Destination> listDest = mapper.Map<Source[], List<Destination>>(sources);Destination[] arrayDest = mapper.Map<Source[], Destination[]>(sources);

具体来说,支持的源集合类型包括:

  • IEnumerable

  • IEnumerable

  • ICollection

  • ICollection

  • IList

  • IList

  • List

  • Arrays

映射到现有集合时,将首先清除目标集合。如果这不是你想要的,请查看AutoMapper.Collection。

5.1 处理空集合

映射集合属性时,如果源值为 null,则 AutoMapper 会将目标字段映射为空集合,而不是 null。这与 Entity Framework 和 Framework Design Guidelines 的行为一致,认为 C# 引用,数组,List,Collection,Dictionary 和 IEnumerables 永远不应该为 null

5.2 集合中的多态

这个官方的文档不是很好理解。我重新举个例子。实体类如下:

public class Employee{    public int ID { get; set; }    public string Name { get; set; }}public class Employee2 : Employee{    public string DeptName { get; set; }}public class EmployeeDto{    public int ID { get; set; }    public string Name { get; set; }}public class EmployeeDto2 : EmployeeDto{    public string DeptName { get; set; }}

数组映射代码如下:

var config = new MapperConfiguration(cfg =>{    cfg.CreateMap<Employee, EmployeeDto>().Include<Employee2, EmployeeDto2>();    cfg.CreateMap<Employee2, EmployeeDto2>();});IMapper mapper = config.CreateMapper();var employees = new[]{    new Employee { ID = 1, Name = "Tom" },    new Employee2 { ID = 2, Name = "Jerry", DeptName = "R & D" }};var dto = mapper.Map<Employee[], EmployeeDto[]>(employees);

可以看到,映射后,dto 中两个元素的类型,一个是 EmployeeDto,一个是 EmployeeDto2,即实现了父类映射到父类,子类映射到子类。

如果去掉 Include 方法,则映射后 dto 中两个元素的类型均为 EmployeeDto

6 方法到属性映射

AutoMapper 不仅能实现属性到属性映射,还可以实现方法到属性的映射,并且不需要任何配置,方法名可以和属性名一致,也可以带有 Get 前缀。

例如下例的 Employee.GetFullName() 方法,可以映射到 EmployeeDto.FullName 属性。

public class Employee{    public int ID { get; set; }    public string FirstName { get; set; }    public string LastName { get; set; }    public string GetFullName()    {        return $"{FirstName} {LastName}";    }}public class EmployeeDto{    public int ID { get; set; }    public string FirstName { get; set; }    public string LastName { get; set; }    public string FullName { get; set; }}

7 自定义映射

当源类型与目标类型名称不一致时,或者需要对源数据做一些转换时,可以用自定义映射。

public class Employee{    public int ID { get; set; }    public string Name { get; set; }    public DateTime JoinTime { get; set; }}public class EmployeeDto{    public int EmployeeID { get; set; }    public string EmployeeName { get; set; }    public int JoinYear { get; set; }}

如上例,IDEmployeeID 属性名不同,JoinTimeJoinYear 不仅属性名不同,属性类型也不同。

var config = new MapperConfiguration(cfg =>{    cfg.CreateMap<Employee, EmployeeDto>()        .ForMember("EmployeeID", opt => opt.MapFrom(src => src.ID))        .ForMember(dest => dest.EmployeeName, opt => opt.MapFrom(src => src.Name))        .ForMember(dest => dest.JoinYear, opt => opt.MapFrom(src => src.JoinTime.Year));});

8 扁平化映射

对象-对象映射的常见用法之一是将复杂的对象模型并将其展平为更简单的模型。

public class Employee{    public int ID { get; set; }    public string Name { get; set; }    public Department Department { get; set; }}public class Department{    public int ID { get; set; }    public string Name { get; set; }}public class EmployeeDto{    public int ID { get; set; }    public string Name { get; set; }    public int DepartmentID { get; set; }    public string DepartmentName { get; set; }}

如果目标类型上的属性,与源类型的属性、方法都对应不上,则 AutoMapper 会将目标成员名按驼峰法拆解成单个单词,再进行匹配。例如上例中,EmployeeDto.DepartmentID 就对应到了 Employee.Department.ID

8.1 IncludeMembers

如果属性命名不符合上述的规则,而是像下面这样:

public class Employee{    public int ID { get; set; }    public string Name { get; set; }    public Department Department { get; set; }}public class Department{    public int DepartmentID { get; set; }    public string DepartmentName { get; set; }}public class EmployeeDto{    public int ID { get; set; }    public string Name { get; set; }    public int DepartmentID { get; set; }    public string DepartmentName { get; set; }}

Department 类中的属性名,直接跟 EmployeeDto 类中的属性名一致,则可以使用 IncludeMembers 方法指定。

var config = new MapperConfiguration(cfg =>{    cfg.CreateMap<Employee, EmployeeDto>().IncludeMembers(e => e.Department);    cfg.CreateMap<Department, EmployeeDto>();});

9 嵌套映射

有时,我们可能不需要展平。看如下例子:

public class Employee{    public int ID { get; set; }    public string Name { get; set; }    public int Age { get; set; }    public Department Department { get; set; }}public class Department{    public int ID { get; set; }    public string Name { get; set; }    public string Heads { get; set; }}public class EmployeeDto{    public int ID { get; set; }    public string Name { get; set; }    public DepartmentDto Department { get; set; }}public class DepartmentDto{    public int ID { get; set; }    public string Name { get; set; }}

我们要将 Employee 映射到 EmployeeDto,并且将 Department 映射到 DepartmentDto

var config = new MapperConfiguration(cfg =>{    cfg.CreateMap<Employee, EmployeeDto>();    cfg.CreateMap<Department, DepartmentDto>();});
(0)

相关推荐

  • 对象到对象映射-AutoMapper

    概述 AutoMapper 是一个对象-对象映射器,可以将一个对象映射到另一个对象. 用来解决一个看似复杂的问题,这种类型的代码编写起来相当枯燥乏味, 官网地址: http://automapper. ...

  • Linq操作ArrayList

    ArrayList实现了System.Collections空间下的IEnumerable接口,这个接口是非泛型的.如果要使用LINQ,必须声明枚举变量的类型,依赖Cast查询运算符转换枚举类型. u ...

  • .NetCore对接各大财务软件凭证API——金蝶系列(1)

    哈喽,又和大家见面了,虽然看文章的小伙伴不多,但是我相信总有一天,自己写的这些文章或多或少会对其他人有些帮助,让他们在相关的业务开发下能少走些弯路,那我的目的就达到了,好了,今天就正式开始我们的系列了 ...

  • 【健康】超全高血压生活手册,每个人都该看看!

    得了高血压,生活中都得注意啥?这儿有一份贴心的高血压生活手册,希望对你有帮助! 一.量血压篇 1 量血压用哪只手?数值高那只!     一般主要工作的手臂,血压会较高一些,比如右手工作的人右手的血压较 ...

  • 【经方使用手册】半夏厚朴汤​

    [经方使用手册]半夏厚朴汤 半夏厚朴汤是经典的情志病方,传统的理气化痰方,具有利咽喉.止呕吐.除胀满.止咳喘.定眩悸等功效.现代研究提示能抗焦虑.抗抑郁.镇静催眠.抑制咽喉反射.调节胃肠蠕动等.适用于 ...

  • 你以为的好习惯,其实是老年痴呆元凶!(含最全防治手册)

    老年痴呆,又叫阿尔兹海默症,也被称为上帝最恶毒魔咒. 从某种意义上来说,它比癌症还可怕.至今病因未明,没有药物可以治愈,只能缓解. 从小事开始遗忘,到最后忘了自己是谁,失去认知.思考.自理能力的同时, ...

  • 【总结】有三AI视觉算法工程师成长指导手册不更新了?不,换视频更新了!

    早期的粉丝们想必还记得我们之前发布的400多页的视觉算法工程师成长指导手册,光是在咱们公众号后台就有超过5000的下载量,已经有段时间没有更新了,因此有小伙伴问我们是不是不更新了,答案是会更新!而且这 ...

  • 地下室防渗漏工艺工法手册,23张节点做法卡片!

    整理 | 豆丁施工 桩头防水构造节点施工工艺 风险与通病:桩头部位防水控制不到位,底板渗水 工艺展示: 工艺标准(质量验收标准): 1.桩头要剔除到设计标高,并用聚合物水泥砂浆找平桩侧剔除至混凝土密实 ...

  • 黄煌经方手册。004 白头翁汤

    004 白头翁汤 经典的厥阴病方,传统的清热解毒方,具有止血痢.解热毒.利肛肠的功效. 现代研究提示能抗肿瘤.抗炎.抗菌.抗原虫真菌.调节免疫.促进肠道黏膜修复等. 适用于里急后重.口干舌燥.脉滑数为 ...

  • 黄煌经方手册 005 补中益气汤

    005 补中益气汤 古代的内伤发热专方,传统的补气升阳方, 具有退虚热.抗劳倦.止自汗.健脾胃的功效.现代研究提示能抗抑郁.保护神经.调节免疫.抗病毒.促进精子活力.减轻放射损伤等. 适用于以反复发热 ...

  • 黄煌经方手册。(四版)序言

    序言 这本小册子问世已经10个年头了.10年前,为了规范用药.方便查阅,我们把 40多首常用经方的适用人群.病症和经典原文等,编印成一本3万字的口袋书,书名<经方使用手册>.这就是本书的雏 ...

  • 继任计划--操作手册

    一.什么是继任计划? 继任计划是选择和培养关键人才以确保关键角色连续性的过程.如果我们看一下这个定义,我们会看到多个突出的要素. 首先,继任计划是关于关键角色的,并非所有角色都相关.它应该关注对组织的 ...