ABP官方文档翻译 2.7 对象到对象的映射
对象到对象的映射
介绍
映射一个相似的对象到另一个对象是常有的事情。因为两个对象(类)有相似/相同的属性,所以两个相似对象之间相互映射是乏味、重复的。考虑一个经典的应用服务方法如下:
public class UserAppService : ApplicationService
{
private readonly IRepository<User> _userRepository; public UserAppService(IRepository<User> userRepository)
{
_userRepository = userRepository;
} public void CreateUser(CreateUserInput input)
{
var user = new User
{
Name = input.Name,
Surname = input.Surname,
EmailAddress = input.EmailAddress,
Password = input.Password
}; _userRepository.Insert(user);
}
}
CreateUserInput是一个简单的DTO,User是一个简单的实体。我们根据给定的input手动创建了一个User实体。在实际的应用中,用户实体会有许多的属性,手动创建它变得乏味且容易出错的。当我们想给User和CreateUserInput添加新属性时,需要改变映射代码。
我们可以使用一个类库来自动映射。AutoMapper是对象到对象映射最好的类库之一。ABP定义了IObjectMapper接口进行抽象,并在Abp.AutoMapper包里使用AutoMapper实现了这个接口。
IObjectMapper接口
IObjectMapper是一个简单的抽象,它包含Map方法用来映射一个对象到另一个。我们可以把上面的实例代码修改如下:
public class UserAppService : ApplicationService
{
private readonly IRepository<User> _userRepository;
private readonly IObjectMapper _objectMapper; public UserAppService(IRepository<User> userRepository, IObjectMapper objectMapper)
{
_userRepository = userRepository;
_objectMapper = objectMapper;
} public void CreateUser(CreateUserInput input)
{
var user = _objectMapper.Map<User>(input);
_userRepository.Insert(user);
}
}
Map是一个简单的方法,获取源对象并使用声明的泛型参数(本例中为User)创建一个新目标对象。Map方法有一个重载,可以映射一个对象到一个已存在的对象。假定我们已经有了一个User实体,想使用一个对象更新它的属性:
public void UpdateUser(UpdateUserInput input)
{
var user = _userRepository.Get(input.Id);
_objectMapper.Map(input, user);
}
AutoMapper集成
Abp.AutoMapper nuget包(模块)实现了IObjectMapper且提供了额外的特征。
安装
首先,在工程中安装Abp.AutoMapper包:
Install-Package Abp.AutoMapper
然后,添加AbpAutoMapperModule依赖到模块定义类中:
[DependsOn(typeof(AbpAutoMapperModule))]
public class MyModule : AbpModule
{
...
}
然后就可以在代码里安全的注入和使用IObjectMapper。当需要的时候,也可以使用AutoMapper自己的API。
创建映射
AutoMapper需要定义一个类之间的映射在使用它之前。可以参见AutoMapper的文档了解关于映射的更多详情。ABP简化了映射并且将它模块化了。
自动映射属性
大多数时候,只想直接(惯例的)映射类。在这种情况下,可以使用AutoMap、AutoMapFrom和AutoMapTo特性。例如,在上面的实例中,我们想映射CreateUserInput类到User类,我们可以按如下所示使用AutoMapTo特性。
[AutoMapTo(typeof(User))]
public class CreateUserInput
{
public string Name { get; set; } public string Surname { get; set; } public string EmailAddress { get; set; } public string Password { get; set; }
}
AutoMap特性双向映射两个类。但是在这个实例中,我们仅仅需要从CreateUserInput类映射到User类,所以我们使用AutoMapTo。
自定义映射
在某些情况下简单映射可能不适合。例如,两个类的属性名称可能有些不一样的或者在映射的时候想要忽略一些属性。在这种情况下,可以直接使用AutoMapper的API定义映射。Abp.AutoMapper包定义了API,使自定义映射模块化。
假定我们映射时想忽略Password,用户用Email属性来标示email地址。我们可以按如下所示定义映射:
[DependsOn(typeof(AbpAutoMapperModule))]
public class MyModule : AbpModule
{
public override void PreInitialize()
{
Configuration.Modules.AbpAutoMapper().Configurators.Add(config =>
{
config.CreateMap<CreateUserInput, User>()
.ForMember(u => u.Password, options => options.Ignore())
.ForMember(u => u.Email, options => options.MapFrom(input => input.EmailAddress));
});
}
}
AutoMapper有许多选项和功能用来映射对象。参见文档了解更多。
MapTo扩展方法
推荐注入并使用IObjectMapper接口,如之前定义的那样。这使我们的工程尽可能的独立于AutoMapper。这也使得单元测试更加容易,因为我们可以在单元测试中替换(模拟)这个映射。
Abp.AutoMapper模块还定义了MapTo扩展方法,可以用到任何对象,将其映射到其他的对象,而不需要注入IObjectMapper。示例用法:
public class UserAppService : ApplicationService
{
private readonly IRepository<User> _userRepository; public UserAppService(IRepository<User> userRepository)
{
_userRepository = userRepository;
} public void CreateUser(CreateUserInput input)
{
var user = input.MapTo<User>();
_userRepository.Insert(user);
} public void UpdateUser(UpdateUserInput input)
{
var user = _userRepository.Get(input.Id);
input.MapTo(user);
}
}
MapTo扩展方法定义在Abp.AutoMapper命名空间,所以需要首先在代码文件里导入这个命名空间。
因为MapTo扩展方法是静态的,他们使用AutoMapper的静态实例(Mapper.Instance)。对应用代码来说,这是简单且友好的,但是在单元测试中会存在问题,因为静态配置和映射在不同测试中是共享的,他们可能会互相影响。
单元测试
我们希望使测试之间是独立的。为了达到这个目的,我们应该按如下规则设计我们的工程:
1. 总是使用IObjectMapper,不使用MapTo扩展方法。
2. 配置Abp.AutoMapper模块使用本地映射实例(使用单例模式注册到依赖注入)而不是静态实例(Abp.AutoMapper默认使用Mapper.Instance实例,这样就允许使用MapTo扩展方法)。
Configuration.Modules.AbpAutoMapper().UseStaticMapper = false;
预定义映射
LocalizableString->string
Abp.AutoMapper模块定义了一个映射,用来转换本地字符串(或者ILocalizableString)对象到string对象。它使用ILocalizationManager进行转换,所以localizable属性在任何类的映射过程中会自动本地化。
注入IMapper
可能需要直接使用AutoMapper的IMapper对象而不是IObjectMapper抽象。在这种情况下,在类中注入并使用IMapper。Abp.AutoMapper包以单例形式将IMapper注册到依赖注入。
ABP官方文档翻译 2.7 对象到对象的映射的更多相关文章
- ABP官方文档翻译 4.3 校验数据传输对象
校验数据传输对象 校验简介 使用数据标注 自定义校验 禁用校验 标准化 校验简介 应用的输入首先应该被校验.输入可以是用户的也可以是其他应用的.在一个web应用中,校验通常实现两次:客户端和服务端.客 ...
- 0.0 ABP官方文档翻译目录
一直想学习ABP,但囿于工作比较忙,没有合适的契机,当然最重要的还是自己懒.不知不觉从毕业到参加工作七年了,没留下点儿什么,总感觉很遗憾,所以今天终于卯足劲鼓起勇气开始写博客.有些事能做的很好,但要跟 ...
- ABP官方文档翻译 6.4 导航
导航 创建菜单 注册导航提供者 显示菜单 每一个网络应用都会有一些菜单用来在pages/screens之间导航.ABP提供了通用的基础设施来创建并显示菜单. 创建菜单 应用可以由不同的模块组成,每一个 ...
- ABP官方文档翻译 2.2 ABP会话
ABP会话 介绍 关于IAbpSession 注入会话 会话属性 覆盖当前会话值 警告! 用户标示 介绍 如果应用需要登录的话,同样也需要知道当前用户可以执行哪些操作.ABP在展现层提供了会话对象,同 ...
- ABP官方文档翻译 0.0 ABP官方文档翻译目录
一直想学习ABP,但囿于工作比较忙,没有合适的契机,当然最重要的还是自己懒.不知不觉从毕业到参加工作七年了,没留下点儿什么,总感觉很遗憾,所以今天终于卯足劲鼓起勇气开始写博客.有些事能做的很好,但要跟 ...
- ABP官方文档翻译 4.2 数据传输对象
数据传输对象 DTOs的必要性 领域层的抽象 数据隐藏 序列化和懒加载问题 DTO转换和验证 示例 DTOs和实体间的自动映射 辅助接口和类 数据传输对象用来在应用层和展示层之间传输数据. 展示层调用 ...
- ABP官方文档翻译 3.2 值对象
值对象 介绍 值对象基类 最佳实践 介绍 "展现领域描述性层面且没有概念性身份的对象称之为值对象."(Eric Evans). 和实体相反,实体有身份标示(Id),值对象没有身份标 ...
- ABP官方文档翻译 10.1 ABP Nuget包
ABP Nuget包 Packages Abp Abp.AspNetCore Abp.Web.Common Abp.Web Abp.Web.Mvc Abp.Web.Api Abp.Web.Api.OD ...
- ABP官方文档翻译 2.5 设置管理
设置管理 介绍 关于 ISettingStore 定义设置 设置范围 重写设置定义 获取设置值 服务端 客户端 更改设置 关于缓存 介绍 每个应用都需要存储设置,并且在应用的某些地方需要使用这些设置. ...
随机推荐
- C++ STL之min_element()与max_element()(取容器中的最大最小值)
min_element()和max_element 头文件:#include<algorithm> 作用:返回容器中最小值和最大值.max_element(first,end,cmp);其 ...
- android仿微信红包动画、Kotlin综合应用、Xposed模块、炫酷下拉视觉、UC浏览器滑动动画等源码
Android精选源码 仿微信打开红包旋转动画 使用Kotlin编写的Android应用,内容你想象不到 Android手机上的免Root Android系统日志Viewer 一个能让微信 Mater ...
- kafka数据迁移实践
欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 作者:mikealzhou 本文重点介绍kafka的两类常见数据迁移方式:1.broker内部不同数据盘之间的分区数据迁移:2.不同broker ...
- 《SpringMVC从入门到放肆》五、SpringMVC配置式开发(处理器适配器)
上一篇我们大致讲解了处理器映射器的处理流程以及跟了一下源码的执行流程.今天我们来了解一下处理器适配器. 一.适配器模式 在阎宏博士的<JAVA与模式>一书中开头是这样描述适配器(Adapt ...
- web框架前言与学生数据库系统(附1.0源码)
对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. import socket def f1(request): ""&quo ...
- Java ASM介绍
一.什么是ASM 首先看下官方中的说明 ASM a very small and fast Java bytecode manipulation framework. ASM是一个JAVA字节码分析. ...
- ntp 时钟同步
注意: 如果你无法和外部网络的时钟同步,请检查UDP端口时候被封.
- 读《你不知道的JavaScript(上卷)》后感-浅谈JavaScript作用域(一)
原文 一. 序言 最近我在读一本书:<你不知道的JavaScript>,这书分为上中卷,内容非常丰富,认真细读,能学到非常多JavaScript的知识点,希望广大的前端同胞们,也入手看看这 ...
- jsp页面遍历List<Array>
不难的遍历,难住了“前辈”,因此决定分享一下希望帮助那些还迷糊的人. 数据结构下如图所示,之前的前辈遍历方法如下,厉害哦!当然,代码直接抛异常哈, <c:if test="${!emp ...
- CSS选择器的新用法
前面的话 现在,预处理器(如sass)似乎已经成为开发CSS的标配,正如几年前jQuery是开发JS的标配一样.JS的querySelector借鉴了jQuery的选择器思想,CSS选择器也借鉴了预处 ...