ABP文档 - 对象与对象之间的映射

文档目录

本节内容:

  • 简介
  • IObjectMapper 接口
  • 集成 AutoMapper
    • 安装
    • 创建映射
      • 自动映射的特性
      • 自定义映射
    • 扩展方法 MapTo
    • 单元测试
    • 预定义的映射
      • LocalizableString -> string
    • 注入 IMapper

简介

把一个对象映射到另一个相似的对象很常见,两个对象(类)具有相似或相同的属性,它们之间要互相映射,其实这项工作重复且无聊,考虑一个典型的应用服务方法,如下:

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作为单例注册到了依赖注入系统里。

时间: 2025-01-24 06:05:25

ABP文档 - 对象与对象之间的映射的相关文章

JAVA对象和XML文档、原来他们之间还有这一出

最近项目开发中遇到一个问题,访问接口不再通过url地址请求的方式,而是 通过socket发送xml格式的报文到指定服务器来进行信息的统一认证.. 因此组装xml格式的报文字符串以及解析服务器返回的xml格式的字符获得所需数据成了 解决问题的关键..在这之前,以为会有点难...做完之后,然并卵,也就那么一回事... LZ主要用的xStream类..这个类的完美地解决了XML文档和JAVA对象之间的转换.. 由于刚刚接触这个类...对于里面提供的很多功能还没细细挖掘..只是简单地实现了 我想要实现的

iOS文档序列化(对象归档)

对象归档: 概念: 对象归档是指将对象写入文件保存在硬盘,当再次重新打开程序时,可以还原这些对象.也称:对象序列化.对象持久化. 数据持久性的方式(其实就是3类) 1,NSKeyedArchiver--对象归档 2,NSUserDefaults  3,属性列表 4,SQLite数据库  5,Core Data数据库 归档方式: 对Foundation库中对象进行归档 自定义对象进行归档(需要实现归档协议,NSCoding) 归档与属性列表的区别: 1,归档后的文件是加密的,属性列表是明文的. 2

OC --(4)--NSString、NSArray、NSNumber、使用苹果帮助文档、值对象

BOOL 类型用 %d  输出 NSRange range={11,7};//结构体赋值用{} NSMakeRange(11, 7);  //快速创建的方法 1.NSString initWithFormat:方法 通过给定格式化字符串 复制给字符串对象赋值 stringWithFormat: 方法其实内部就是 alloc+initWithFormat: NSString *str2=[NSString stringWithFormat:@"chu cuo le "]; 2.获取长度

&lt;&lt;ABP文档&gt;&gt; 导航

文档目录 本节内容: 创建菜单 注册导航供应器 显示菜单 每个web应用都有一些菜单用来在页面/屏幕之间导航,ABP提供了一个通用的基础框架创建并显示菜单给用户. 创建菜单 一个应用可能由不同模块组成,每个模块可以有它自己的菜单项,为了定义菜单项,我们需要创建一个继承于NavigationProvider的类. 假设有一个如下所示的主菜单: Tasks Reports Administration User management Role management 这里,Administration

&lt;&lt;ABP文档&gt;&gt; 异常处理

文档目录 本节内容: 简介 启用错误处理 非AJAX请求 显示异常 UserFriendlyException Error 模型 AJAX 请求 异常事件 简介 这个方法针对Asp.net Mvc和Web Api,如果你对Asp.net Core感兴趣,请看Asp.net Core文档. 在一个Web应用里,异常通常在Mvc控制器的Action或Web Api 控制器的Action里被处理,当一个异常姓时,应用的用户会通过某种方式收到错误信息和错误的可能原因. 如果一个错误发生在平常的HTTP请

&lt;&lt;ABP文档&gt;&gt; 通知系统

文档目录 本节内容: 简介 发送模式 通知类型 通知数据 通知重要性 关于通知持久化 订阅通知 发布通知 用户通知管理器 实时通知 客户端 通知存储 通知定义 简介 通知用来告知用户系统里特定的事件发生了,ABP提供一个发布/订阅,它基于实时通知基础框架. 发送模式 有两种方式可以发送通知给用户: 用户订阅一个特定的通知类型,然后我们发布一个此类型的通知,它会分发给所有订阅的用户,这就是发布/订阅模式. 我们可以直接发送一个通知给目标用户(users). 通知类型 有两种通知类型: 一般通知:任

&lt;&lt;ABP文档&gt;&gt; EntityFramework 集成

文档目录 本节内容: Nuget 包 DbContext 仓储 默认仓储 自定义仓储 特定的仓储基类 自定义仓储示例 仓储最佳实践 ABP可使用任何ORM框架,它已经内置了EntityFrame(以下简称EF),这个文档将解释如何在ABP里使用EF,我们假设你对EF已经有初步的了解. Nuget 包 在ABP里使用EF的Nuget包是Abp.EntityFramework,你应该把它加入到你的应用里,最好在你项目里单独建立一个EF程序集(dll),然后依赖该于这个包. DbContext 如你所

&lt;&lt;ABP文档&gt;&gt; SignalR 集成

文档目录 本节内容: 简介 安装 服务端 客户端 连接确立 内置功能 通知 在线客户端 帕斯卡 vs 骆峰式 你的SignalR代码 简介 使用Abp.Web.SignalR nuget包,使基于应用的ABP使用SignalR非常容易,查看SignalR文档了解SignalR的明细信息. 安装 服务端 在你的项目(通常是你的Web层)里安装Abp.Web.SignalRnuget包并在你的模块上添加对它的依赖: [DependsOn(typeof(AbpWebSignalRModule))] p

&lt;&lt;ABP文档&gt;&gt; Javascript Api

文档目录 本节内容: AJAX Notification Message UI Block & Busy Event Bus Logging Other Utility Functions ABP提供了一序列的对象和功能,使javascript开发容易且标准. 此处有一个ABP里api的列表,点击标题查看明细和使用方法. AJAX 使用AJAX调用服务端服务并计算返回值,因为ABP服务端代码返回一个标准的响应给AJAX调用,所以建议使用这个方法处理标准的返回值. Notification 显示自