写博客的过程中,发现很多基础理论太薄弱,因此很多专业词汇可能会解释错误或者不准确,建议读者多参考官方文档或者其它书籍。

本篇主要讲解 ABP 中如何配置、使用对象映射,其中大部分跟 AutoMapper 这个框架有关,建议读者预先学习这个框架,可参考笔者的另一篇博客:浅入 AutoMapper

基础

DTO和实体

实体

实体是领域驱动设计(Domain Driven Design)中的概念,实体通常一一映射某些对象的固有属性,最常使用的是关系型数据库中的表。

在 ABP 中,实体位于领域层中,实体类需要实现 IEntity<TKey> 接口或继承 Entity<TKey> 基类,示例如下:

  1. public class Book : Entity<Guid>
  2. {
  3. public string Name { get; set; }
  4. public float Price { get; set; }
  5. }

DTO

数据传输对象(Data Transfer Object),作为数据传输过程中的数据模型,用于在应用层和表示层之间传输数据。

在 ABP 中,DTO 位于应用服务层,即本系列文章示例源码中的 AbpBase.Application 项目。

通常表示层或其它类型的客户端调用应用服务时,将 DTO 作为参数传递,它使用领域对象(实体)执行某些特定的业务逻辑,并将 DTO (跟传入的 DTO 不是同一个)返回到表示层中,因此表示层与领域层完全隔离。

DTO 类 可能会跟 实体类的字段/属性高度相似,为每个服务的每个方法创建 DTO 类可能会很枯燥且费时间。

ABP 的 DTO 类示例如下:

  1. public class ProductDto : EntityDto<Guid>
  2. {
  3. public string Name { get; set; }
  4. //...
  5. }

麻烦的映射

前面提到,领域层和应用服务层是要隔离的,例如以下伪代码:

  1. class HomeController
  2. {
  3. AddService _service;
  4. [HttpPost]
  5. public int AddEquip(EquipDto dto)
  6. {
  7. return _service.Add(dto).Id;
  8. }
  9. }
  10. class AddService
  11. {
  12. DataContext _context;
  13. EquipDto Add(EquipDto dto)
  14. {
  15. Equip equip = new Equip()
  16. {
  17. Name = dto.Name;
  18. };
  19. _context.Equip.Add(equip);
  20. _context.SaveChange();
  21. dto.Id = equip.Id;
  22. return dto;
  23. }
  24. }
  25. class EquipDto
  26. {
  27. int Id;
  28. string Name;
  29. }
  30. ----------
  31. class Equip
  32. {
  33. int Id;
  34. string Name;
  35. }

这样每次都需要手动为 DTO 类和 实体类手动对字段赋值映射,当一个实体有数十个字段时,写出的代码会很冗长,而且容易忽略了某些字段,最终导致了 Bug。

大家都知道, AutoMapper 正好可以解决这个问题。

AutoMapper 集成

ABP 的 Volo.Abp.AutoMapper 模块封装或集成了 AutoMapper,所以我们正好使用模块,为 ABP 应用定义对象映射。

关于 AutoMapper 的使用,如何配置 Profile 等,笔者已经单独写到 浅入 AutoMapper,请点击链接另外学习 AutoMapper 的使用。

我们可以在 AbpBase.Application 项目中,新建 一个 AbpBaseApplicationAutoMapperProfile.cs 文件,这个文件用于实现 Profile 以及定义映射。将服务领域的映射集中到这个文件中;或者新建一个 Profiles 文件夹,在其中存放一些 Profile 类。

其内容如下:

  1. public class AbpBaseApplicationAutoMapperProfile:Profile
  2. {
  3. public AbpBaseApplicationAutoMapperProfile()
  4. {
  5. //base.CreateMap<MyEntity,MyDto>();
  6. }
  7. }

定义完毕后,需要配置 AutoMapper 依赖注入,可在 AbpBaseApplicationModuleConfigureServices 方法中,增加以下代码:

  1. Configure<AbpAutoMapperOptions>(options =>
  2. {
  3. // 以模块为单位注册映射
  4. options.AddMaps<AbpBaseApplicationModule>();
  5. //// 以单个 Profiel 为单位注册映射
  6. //options.AddProfile<AbpBaseApplicationAutoMapperProfile>();
  7. });

在 Debug 阶段,我们担心项目改动代码时,新增的字段忘记了加入到映射配置中,或者其它情况,在 AutoMapper 中,我们可以使用 configuration.AssertConfigurationIsValid(); 来检查映射;在 ABP 中则可使用 validate: true 参数来开启检查。

  1. Configure<AbpAutoMapperOptions>(options =>
  2. {
  3. // 以模块为单位注册映射
  4. options.AddMaps<AbpBaseApplicationModule>(validate: true);
  5. //// 以单个 Profiel 为单位注册映射
  6. //options.AddProfile<AbpBaseApplicationAutoMapperProfile>(validate: true);
  7. });

IObjectMapper/ObjectMapper

AbpBase.Application 项目中,添加 Nuget 包,搜索 Volo.Abp.ObjectMapping 并下载相应的稳定版本。

IObjectMapper 有两个,一个是 AutoMapper 的接口,一个是 Volo.Abp.ObjectMapping 的 泛型接口。

AutoMapper 的 IObjectMapper 不好用,所以别用;用 Volo.Abp.ObjectMappingIObjectMapper <接口>

ObjectMapper 是 AutoMapper 中的,我们可以直接在控制器等位置,使用 ObjectMapper 注入,然后通过 ObjectMapper 实例映射对象。

ObjectMapper 只有 .Map() 这个方法用得顺手。

  1. private readonly ObjectMapper<T1,T2> _mapper;
  2. public TestController(ObjectMapper<T1,T2> mapper)
  3. {
  4. _mapper = mapper;
  5. // ... 使用示例
  6. _ = mapper.Map<T1> ();
  7. }

也可以通过依赖注入使用 IObjectMapper 接口。

但是因为 ObjectMapper 是泛型类,每种类型的 DTO 都要注入一次的话,会很麻烦,因此这种方案也可以抛弃。

而 泛型的 IObjectMapper<TModule> 是一个抽象,我们使用 IObjectMapper<TModule> 做依赖注入的话,后续如果替换为别的对象映射框架,则不需要修改原有代码即可完成替代。而且 IObjectMapper<TModule> 比较舒服。

使用示例:

  1. private readonly IObjectMapper<AbpBaseApplicationModule> _mapper;
  2. public TestController(IObjectMapper<AbpBaseApplicationModule> mapper)
  3. {
  4. _mapper = mapper;
  5. // ... 使用示例
  6. _ = mapper.Map<...>();
  7. }

对象拓展

ABP框架提供了 实体扩展系统 允许你 添加额外属性 到已存在的对象 无需修改相关类。这句话是抄 ABP 官方文档的。

要支持对象拓展映射,则需要开启配置:

  1. public class MyProfile : Profile
  2. {
  3. public MyProfile()
  4. {
  5. CreateMap<User, UserDto>()
  6. .MapExtraProperties();
  7. }
  8. }

时间有限,笔者这里只把官方文档的内容讲清楚,读者看完后,需要继续查阅官方文档,完整了解对象拓展。

ObjectExtensionManager 是一个拓展对象映射类,可以显式为类拓展一些额外的属性,这个类型在 Volo.Abp.ObjectMapping 中定义。

ObjectExtensionManager 是一个类型,但是我们不能直接 new 它,或者使用依赖注入,只能通过 ObjectExtensionManager.Instance 这个属性获取新的类型。我们无需关心它是用了啥设计模式,还是因为缓存之类的原因这样设计。

ObjectExtensionManager 有两种属性,其说明如下:

  • AddOrUpdate :是定义对象额外属性或更新对象额外属性的主要方法;
  • AddOrUpdateProperty:快捷地定义单个拓展属性的方法;

AddOrUpdateProperty 用于定义单个属性,AddOrUpdate 是一个容器,可以包含多个 AddOrUpdateProperty

AddOrUpdateProperty 示例代码如下:

  1. ObjectExtensionManager.Instance
  2. .AddOrUpdateProperty<TestA, string>("Name");
  3. // 为 TestA 类添加了一个 G 属性

AddOrUpdate 的示例代码如下:

  1. ObjectExtensionManager.Instance
  2. .AddOrUpdate<TestA>(options =>
  3. {
  4. options.AddOrUpdateProperty<string>("Name");
  5. options.AddOrUpdateProperty<bool>("Nice");
  6. }
  7. );

当然,我们还可以同时为多个类型同时定义一个额外的属性:

  1. ObjectExtensionManager.Instance
  2. .AddOrUpdateProperty<string>(
  3. new[]
  4. {
  5. typeof(TestA),
  6. typeof(TestB),
  7. typeof(TestC)
  8. },
  9. "Name"
  10. );

如果需要定义多个属性,则可以使用 AddOrUpdate

  1. ObjectExtensionManager.Instance
  2. .AddOrUpdate(options =>
  3. {
  4. options.AddOrUpdateProperty<string>("Name");
  5. }, new[]{
  6. typeof(TestA),
  7. typeof(TestB)
  8. });

另外它还可以设置默认值、增加验证规则等,这些笔者就不再赘述,读者感兴趣可以点击链接进入官方文档查看。

https://docs.abp.io/zh-Hans/abp/latest/Object-Extensions#validation

浅入 ABP 系列(7):对象映射的更多相关文章

  1. 浅入 ABP 系列(4):事件总线

    浅入 ABP 系列(4):事件总线 版权护体作者:痴者工良,微信公众号转载文章需要 <NCC开源社区>同意. 目录 浅入 ABP 系列(4):事件总线 事件总线 关于事件总线 为什么需要这 ...

  2. 浅入ABP(1):搭建基础结构的 ABP 解决方案

    浅入ABP(1):搭建基础结构的 ABP 解决方案 目录 浅入ABP(1):搭建基础结构的 ABP 解决方案 搭建项目基础结构 ApbBase.Domain.Shared 创建过程 ApbBase.D ...

  3. 浅入 AutoMapper

    目录 浅入 AutoMapper AutoMapper 基本使用 映射配置 映射检查 性能 Profile 配置 依赖注入 表达式与 DTO 浅入 AutoMapper 在 Nuget 搜索即可安装, ...

  4. ABP(现代ASP.NET样板开发框架)系列之16、ABP应用层——数据传输对象(DTOs)

    点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之16.ABP应用层——数据传输对象(DTOs) ABP是“ASP.NET Boilerplate Project ...

  5. Mybatis源码解析,一步一步从浅入深(四):将configuration.xml的解析到Configuration对象实例

    在Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码中我们看到了XMLConfigBuilder(xml配置解析器)的实例化.而且这个实例化过程在文章:Mybatis源码解析,一步一步从浅 ...

  6. Mybatis源码解析,一步一步从浅入深(六):映射代理类的获取

    在文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码中我们提到了两个问题: 1,为什么在以前的代码流程中从来没有addMapper,而这里却有getMapper? 2,UserDao ...

  7. 基于 abp vNext 和 .NET Core 开发博客项目 - 用AutoMapper搞定对象映射

    上一篇文章(https://www.cnblogs.com/meowv/p/12961014.html)集成了定时任务处理框架Hangfire,完成了一个简单的定时任务处理解决方案. 本篇紧接着来玩一 ...

  8. 浅入深出Vue系列

    浅入深出Vue导航 导航帖,直接点击标题即可. 文中所有涉及到的资源链接均在最下方列举出来了. 前言 基础篇 浅入深出Vue:工具准备之WebStorm搭建及配置 浅入深出Vue之工具准备(二):Po ...

  9. MyBitis(iBitis)系列随笔之二:类型别名(typeAliases)与表-对象映射(ORM)

    类型别名(typeAliases):     作用:通过一个简单的别名来表示一个冗长的类型,这样可以降低复杂度.    类型别名标签typeAliases中可以包含多个typeAlias,如下 < ...

  10. Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码

    在文章:Mybatis源码解析,一步一步从浅入深(一):创建准备工程,中我们为了解析mybatis源码创建了一个mybatis的简单工程(源码已上传github,链接在文章末尾),并实现了一个查询功能 ...

随机推荐

  1. 什么是PWA 应用?核心技术有哪些

    在国内由于小程序的风生水起,PWA 应用在国内的状况一直都不是很好,PWA 和小程序有很多的相似性,但是 PWA 是由谷歌发起的技术,小程序是微信发起的技术,所以小程序在国内得到了大力的扶持,很快就在 ...

  2. echarts更改x和y轴的颜色

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  3. 如何处理开发环境没有问题,线上环境有问题这个bug

    解决思路 首先确认开发环境有没有这个问题: 如果没有这个问题: 将你的地址切换为线上的环境,看看线上环境有没有这个问题: 如果切换为线上环境有这个问题,就可以调试了: 如果切换为线上环境没有这个问题, ...

  4. 基于go-restful实现的PoW算力池模型

    最开始知道区块链是在17年初,当时因为项目压力不大,开始研究比特币源码.对于比特币中提到的Proof of Work,当时只是一眼带过,并没有详细查看过相关的代码.在最近的项目中,考虑到性能的要求,需 ...

  5. 使用三方jar中的@RestControllerAdvice不起作用

    背景 公司封装了自己的基础核心包core-base,里边包含了Validation的异常捕获处理类:同时开发项目有全局异常捕获处理类,经测试发现,core-base里边的不起作用 可能原因: 未扫描外 ...

  6. rpm安装卸载jdk

    安装 rpm -ivh jdk-7-linux-x64.rpm 卸载 先查看安装的包 rpm -qa | grep jdk 卸载 rpm -e --nodeps jdk-1.7.0-fcs.x86_6 ...

  7. P4747 [CERC2017] Intrinsic Interval 题解

    题目链接:Intrinsic Interval 讲讲析合树如何解决这种问题,其实这题很接近析合树的板题的应用. 增量法进行析合树建树时,需要用 ST 表预处理出 \(max\) 和 \(min\) 以 ...

  8. 使用ethtool排查网卡速率问题

    今天去现场帮一个客户排查备份网络速率问题. 用户期望是万兆的速率,但实际上目前只有千兆,因为目前上面运行着数据库,且数据量较大,千兆的备份网络速率不能满足用户备份数据库的时长要求. 首先,确认备份网络 ...

  9. 小知识:在Exadata平台上使用ExaWatcher收集信息

    在非Exadata平台上,我们通常会使用DBA已经很熟悉的OSW,如果有不熟悉的朋友可以参考我之前的随笔初步了解OSW: OSW 快速安装部署 OSW Analyzer分析oswbb日志发生异常 而在 ...

  10. Hive压缩和存储

    1.压缩 (1)Hive支持的压缩编码 压缩格式 工具 算法 文件扩展名 是否可切分 对应的编码/解码器 DEFLATE 无 DEFLATE .deflate 否 org.apache.hadoop. ...