ABP框架系列之四十二:(Object-To-Object-Mapping-对象映射)
Introduction
It's a common to map a similar object to another object. It's also tedious and repeating since generally both objects (classes) may have similar/same properties mapped to each other. Think on a typical application servicemethod below:
将相似的对象映射到另一个对象是很常见的。这也是乏味和重复的,因为一般两个对象(类)可能具有相似的/相同的属性映射到彼此。想象在一个典型的应用服务的方法:
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 is a simple DTO and User is a simple entity here. We manually created a User entity from given input. User entity will have much more properties in a real world application and manually creating it will become tedious and error-prone. Also, we should change the mapping code when we want to add new properties to User and CreateUserInput.
createuserinput是一个简单的DTO和用户这是一个简单的实体。我们从给定输入手动创建了一个用户实体。用户实体在实际应用程序中具有更多的属性,手工创建它将变得单调乏味,容易出错。同时,我们应该改变映射的代码时,我们要对用户和createuserinput添加新的属性。
We can use a library to make this mapping automatically. AutoMapper is one of the best libraries for object to object mapping. ASP.NET Boilerplate defines IObjectMapper interface to abstract it and implements this interface using AutoMapper in Abp.AutoMapper package.
我们可以使用一个库来自动绘制这个映射。AutoMapper是一个对象到对象的映射最好的库。ASP.NET的模板定义iobjectmapper接口抽象和实现这个接口使用AutoMapper Abp.AutoMapper包。
IObjectMapper Interface
IObjectMapper is a simple abstraction that has Map methods to map an object to another. We can write the sample code above as like below:
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 is a simple method gets the source object and creates a new destination object with the type declared as the generic parameter (User in this sample). Map method has an overload to map an object to an existing object. Assume that we already have a User entity and want to update it's properties by an object:
map是获取源对象并创建一个新的目标对象的简单方法,该对象声明为泛型参数(本示例中的用户)。映射方法具有将对象映射到现有对象的重载。假设我们已经有一个用户实体,并且想通过对象更新它的属性:
public void UpdateUser(UpdateUserInput input)
{
var user = _userRepository.Get(input.Id);
_objectMapper.Map(input, user);
}
AutoMapper Integration
Abp.AutoMapper nuget package (module) implements IObjectMapper and provides additional features.
Installation
First, install Abp.AutoMapper nuget to your project:
Install-Package Abp.AutoMapper
Then add a dependency for AbpAutoMapperModule to your module definition class:
[DependsOn(typeof(AbpAutoMapperModule))]
public class MyModule : AbpModule
{
...
}
Then you can safely inject and use IObjectMapper in your code. You can also use AutoMapper's own API when you need.
Creating Mappings
AutoMapper requires to define mappings between classes (by default) before using the mapping. You can see it's own documentation for details on mapping. ASP.NET Boilerplate makes it a bit easier and modular.
AutoMapper需要定义之间的映射类(默认)在使用映射。关于映射的详细信息,您可以看到它自己的文档。ASP.NET样板使它更简单和模块化。
Auto Mapping Attributes(自动映射特性)
Most of time you only want to directly (and conventionally) map classes. In that case, you can use AutoMap, AutoMapFrom and AutoMapTo attributes. For instance, as we want to map CreateUserInput class to User class in the sample above, we can use AutoMapTo attribute as shown below:
[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 attribute maps two classes in both direction. But in this sample, we only need to map from CreateUserInput to User, so we used AutoMapTo.
Custom Mapping(自定义映射)
Simple mapping may not be suitable in some cases. For instance, property names of two classes may be a little different or you may want to ignore some properties during the mappping. In such cases you should directly use AutoMapper's API to define the mapping. Abp.AutoMapper package defines API to make this custom mapping stuff more modular.
在某些情况下,简单映射可能不合适。例如,两类属性名称可能有所不同,或者你可能想忽略的一些性质在映射。在这种情况下,你应该直接使用AutoMapper的API来定义映射。abp.automapper包定义API进行自定义映射的东西更加模块化。
Assume that we want to ignore Password on mapping and User has Email property for email address. We can define mapping as shown below:
假设我们希望忽略映射中的密码,用户拥有电子邮件地址的电子邮件属性。我们可以定义映射如下图所示:
[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 has much more options and abilities for object to object mapping. See it's documentation for more.
MapTo Extension Methods(MapTo 扩展方法)
It's suggested to inject and use IObjectMapper interface as defined before. This makes our project independent from AutoMapper as much as possible. It also makes unit testing easier since we can replace (mock) the mapping in unit tests.
Abp.AutoMapper module also defines MapTo extension methods which can be used on any object to map it to another object without injecting IObjectMapper. Example usage:
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 extension methods are defined in Abp.AutoMapper namespace, so you first import this namespaces into your code file.
Since MapTo extension methods are statics, they use AutoMapper's static instance (Mapper.Instance). This is simple and fine for the application code, but can have problems in unit tests since static configuration and mapper is shared among different tests and they may effect each other.
由于扩展方法是静态的,他们使用AutoMapper的静态实例(制图。实例)。这对于应用程序代码来说是简单而精细的,但是单元测试可能会有问题,因为静态配置和映射器在不同的测试中共享,它们可能相互影响。
Unit Tests
We want to isolate tests from each others. To do that, we should design our project with the following rules:
我们希望从彼此之间分离测试。要做到这一点,我们应该按照以下规则来设计我们的项目:
1. Always use IObjectMapper, not use MapTo extension methods.
2. Configure Abp.AutoMapper module to use local Mapper instance (registered as singleton to dependency injection) rather than the static one (Abp.AutoMapper uses the static Mapper.Instance by default to allow to use MapTo extension methods defined above):
Configuration.Modules.AbpAutoMapper().UseStaticMapper = false;
Pre Defined Mappings(预先定义的映射)
LocalizableString -> string
Abp.AutoMapper module defines a mapping to convert LocalizableString (or ILocalizableString) objects to string objects. It makes the conversion using ILocalizationManager, so localizable properties are automatically localized during the mapping process of any class.
abp.automapper模块定义转换localizablestring映射(或ilocalizablestring)对象的字符串对象。它使转换使用ilocalizationmanager,所以可本地化的属性自动定位的任何类别的映射过程。
Injecting IMapper
You may need to directly use AutoMapper's IMapper object instead of IObjectMapper abstraction. In that case, just inject IMapper in your classes and use it. Abp.AutoMapper package registers IMapper to dependency injectionas singleton.
ABP框架系列之四十二:(Object-To-Object-Mapping-对象映射)的更多相关文章
- ABP框架系列之五十二:(Validating-Data-Transfer-Objects-验证数据传输对象)
Introduction to validation Inputs of an application should be validated first. This input can be sen ...
- ABP框架系列之四十:(Notification-System-通知系统)
Introduction Notifications are used to inform users on specific events in the system. ASP.NET Boiler ...
- ABP框架系列之四十九:(Startup-Configuration-启动配置)
ASP.NET Boilerplate provides an infrastructure and a model to configure it and modules on startup. A ...
- ABP框架系列之三十二:(Logging-登录)
Server Side(服务端) ASP.NET Boilerplate uses Castle Windsor's logging facility. It can work with differ ...
- ABP框架系列之四十六:(Setting-Management-设置管理)
Introduction Every application need to store some settings and use these settings in somewhere in th ...
- ABP框架系列之四十八:(Specifications-规范)
Introduction Specification pattern is a particular software design pattern, whereby business rules c ...
- ABP框架系列之四十四:(OWIN)
If you are using both of ASP.NET MVC and ASP.NET Web API in your application, you need to add Abp.Ow ...
- ABP框架系列之十二:(Audit-Logging-审计日志)
Introduction Wikipedia: "An audit trail (also called audit log) is a security-relevant chronolo ...
- ABP框架系列之四十五:(Quartz-Integration-Quartz-集成)
Introduction Quartz is a is a full-featured, open source job scheduling system that can be used from ...
随机推荐
- 第三章 FFmpeg转封装
3.1 音视频文件转MP4格式 在互联网常见的格式中,跨平台最好的应该是MP4文件. 3.1.1 MP4格式标准介绍 MP4文件由多个Box与FullBox组成 每个Box由Header和Data两部 ...
- Vue的路由实现:hash模式 和 history模式
hash模式:在浏览器中符号“#”,#以及#后面的字符称之为hash,用 window.location.hash 读取.特点:hash虽然在URL中,但不被包括在HTTP请求中:用来指导浏览器动作, ...
- 官方解析Cookies和Session的区别
官方理解: Cookie机制 Cookie机制 Cookie是服务器存储在本地计算机上的小块文本,并随每个请求发送到同一服务器. IETF RFC 2965 HTTP状态管理机制是一种通用的coo ...
- 解决spring-security session超时 Ajax 请求没有重定向的问题
开始时, 代码是这样的: $.ajax({ type : "POST", url : sSource, cache : false, dataType : "json&q ...
- Linux输入子系统详解
input输入子系统框架 linux输入子系统(linux input subsystem)从上到下由三层实现,分别为:输入子系统事件处理层(EventHandler).输入子系统核心层(Input ...
- echart 单选legend 并排序
java代码 List<Map<String, Object>> AllList = null; JSONArray jsonArray = JSONArray.fromObj ...
- JAVA条件判断
一.基本if结构 1.流程图 l 输入输出 l 判断和分支 l 流程线 1.1 简单的if条件判断 if(表达式){ //表达式为true,执行{ ...
- c++冒号作用
转自http://www.360doc.com/content/13/0605/11/3373961_290615318.shtml 1.冒号(:)用法 (1)表示机构内位域的定义(即该变量占几个bi ...
- Element-UI使用指南
原网址:https://blog.csdn.net/u012285967/article/details/53023825 Element-UI是饿了么前端团队推出的一款基于Vue.js 2.0 的桌 ...
- spfa与dijkstra(最短路)
spfa: void spfa(){ queue<int> que; while(!que.empty()){que.pop();} que.push(s); vis[s]=; while ...