ABP文档 - 对象与对象之间的映射
本节内容:
简介
把一个对象映射到另一个相似的对象很常见,两个对象(类)具有相似或相同的属性,它们之间要互相映射,其实这项工作重复且无聊,考虑一个典型的应用服务方法,如下:
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是一个简单的数据传输对象,User是一个简单的实体,我们根据传入的input手工创建一个User实体,现实应用里User实体将会有更多的属性,手工创建它就会变得很无聊且容易出错,而且,当我们添加新的属性到User和CreateUserInput时,又需要修改映射的代码。
其实我们可以用一个类库来自动完成映射,AutoMapper是一个最好的对象到对象的映射类库,Abp中定义了IObjectMapper接口来抽象它,且在 Abp.AutoMapper包中实现了这个接口。
IObjectMapper 接口
IObjectMapper是一个简单的包含把一个对象映射到另一个对象的方法的抽象,我们可以用如下代码书写上例:
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 nuget包到你的项目里:
Install-Package Abp.AutoMapper
然后,在你的模块上方添加对AbpAutoMapperModule 的依赖:
[DependsOn(typeof(AbpAutoMapperModule))]
public class MyModule : AbpModule
{
...
}
接下来,你就可以在你代码里放心地注入和使用IObjectMapper,当然,你如有需要,也可以使用 AutoMapper自身API。
创建映射
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并把用EmailAddress映射到User的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 模块,使用局部的Mapper实例(用单例的方式注册到依赖注入)不用静态的(Abp.AutoMapper默认情况下,使用静态的Mapper.Instance,从而可以像上面那样使用MapTo扩展方法):
Configuration.Modules.AbpAutoMapper().UseStaticMapper = false;
预定义的映射
LocalizableString -> string
Abp.AutoMapper模块定义了一个从LocalizableString (或 ILocalizableString) 对象到string对象的映射,它使用ILoclaizationManager进行转换,所以在映射过程中,可以本地化的属性会自动的本地化。
注入 IMapper
如果你需要注入AutoMapper的IMapper对象来代替IObjectMapper,就直接在你的类里注入IMapper并使用它,Abp.AutoMapper包把IMapper作为单例注册到了依赖注入系统里。
ABP文档 - 对象与对象之间的映射的更多相关文章
- JAVA对象和XML文档、原来他们之间还有这一出
最近项目开发中遇到一个问题,访问接口不再通过url地址请求的方式,而是 通过socket发送xml格式的报文到指定服务器来进行信息的统一认证.. 因此组装xml格式的报文字符串以及解析服务器返回的xm ...
- XML解析之sax解析案例(二)使用sax解析把 xml文档封装成对象
Demo1类: import java.io.File; import java.util.List; import javax.xml.parsers.SAXParser; import javax ...
- ABP文档笔记系列
ABP文档笔记 - 模块系统 及 配置中心 ABP文档笔记 - 事件BUS ABP文档笔记 - 数据过滤 ABP文档笔记 - 规约 ABP文档笔记 - 配置.设置.版本.功能.权限 ABP文档笔记 - ...
- jQuery对标签、类样式、值、文档、DOM对象的操作
jquery的标签属性操作 使用attr()方法对html标签属性进行操作,attr如果参数是一个参数,表示获取html标签的属性值,如果是两个参数则是设置标签属性名以及对象的属性值 .prop()适 ...
- excel文档中嵌入对象(excel、word等)
//测试环境office2016.office365 string InsertPath= @"E:\\新建文件夹\\2.xls";//插入的文档路径 string openfil ...
- ABP文档 - 后台作业和工作者
文档目录 本节内容: 简介 后台作业 关于作业持久化 创建一个后台作业 在队列里添加一个新作业 默认的后台作业管理器 后台作业存储 配置 禁用作业执行 Hangfire 集成 后台工作者 创建一个后台 ...
- ABP文档 - 导航
文档目录 本节内容: 创建菜单 注册导航供应器 显示菜单 每个web应用都有一些菜单用来在页面/屏幕之间导航,ABP提供了一个通用的基础框架创建并显示菜单给用户. 创建菜单 一个应用可能由不同模块组成 ...
- ABP文档 - Javascript Api - AJAX
本节内容: AJAX操作相关问题 ABP的方式 AJAX 返回信息 处理错误 HTTP 状态码 WrapResult和DontWrapResult特性 Asp.net Mvc 控制器 Asp.net ...
- ABP文档 - EntityFramework 集成
文档目录 本节内容: Nuget 包 DbContext 仓储 默认仓储 自定义仓储 特定的仓储基类 自定义仓储示例 仓储最佳实践 ABP可使用任何ORM框架,它已经内置了EntityFrame(以下 ...
随机推荐
- 使文字在div中水平和垂直居中的的css样式为,四个边分别设置阴影样式
text-align:center; /*水平居中*/ line-height: 20px; /*行距设为与div高度一致*/ HTML元素 <div>水平垂直居中</div> ...
- Mongo-Connector 安装及使用文档
# Mongo-Connector 安装及使用文档 ------ > * 工具介绍> * 安装前准备> * 安装步骤> * 命令详解> * 有可能的坑> * 其他文 ...
- HTML5本地图片裁剪并上传
最近做了一个项目,这个项目中需要实现的一个功能是:用户自定义头像(用户在本地选择一张图片,在本地将图片裁剪成满足系统要求尺寸的大小).这个功能的需求是:头像最初剪切为一个正方形.如果选择的图片小于规定 ...
- node.js报错throw err; // Rethrow non-MySQL errors e:\serverTest\node_modules\mysql\lib\protocol\Parser.js:79 解决方法
今天在用node+angular做后台时,需要使用session保存登陆状态的时候,遇到了此问题,问题直译为非mysql问题,我也在后台取到的登陆用户名和密码,确实不是数据库问题.最后发现在使用ses ...
- Mongodb Geo2d索引原理
作者:孔德雨 MongoDB的geo索引是其一大特色,本文从原理层面讲述geo索引中的2d索引的实现. 2d 索引的创建与使用 通过 db.coll.createIndex({"lag&qu ...
- (iOS)私有API的使用(原创)
最近在做企业级程序,需要搞设备的udid等信息,但是ios7把udid私有化了,不公开使用.所以研究了一下ios的私有api. 调查了一下文章,发现这方面的文章不多,国内更是不全,高手们都懒得写基础教 ...
- 《Algorithms Unlocked》读书笔记1——循环和递归
<Algorithms Unlocked>是 <算法导论>的合著者之一 Thomas H. Cormen 写的一本算法基础. 书中没有涉及编程语言,直接用文字描述算法,我用 J ...
- Azure Messaging-ServiceBus Messaging消息队列技术系列8-服务总线配额
上篇博文中我们介绍了Azure ServiceBus Messaging的消息事务机制: Azure Messaging-ServiceBus Messaging消息队列技术系列7-消息事务(2017 ...
- Spring Boot 整合 Redis 实现缓存操作
摘要: 原创出处 www.bysocket.com 「泥瓦匠BYSocket 」欢迎转载,保留摘要,谢谢! 『 产品没有价值,开发团队再优秀也无济于事 – <启示录> 』 本文提纲 ...
- JS为网页添加文字水印【原创】
最近需要实现为网页添加水印的功能,由于水印的信息是动态生成的,而百度谷歌上的方法往往都是为网页添加图片水印或为图片添加水印,而为网页添加文字水印相关资料较少,于是就自己动手写了这个代码. 通常加动态水 ...