如何在 .NetCore 中使用 AutoMapper 高级功能

本文介绍AutoMapper库的高级使用技巧,包括配置、Profiles管理、ReverseMap、ForMember与MapFrom、NullSubstitute、AOP拦截及嵌套映射等。

AutoMapper 是一个基于约定的面向对象的映射器,它的功能常用于将一个 input 对象 转成一个不同类型的 output 对象,inputoutput 对象之间的属性可能相同也可能不相同,这一篇我们来一起研究一下 AutoMapper 的一些高级玩法。

安装 AutoMapper

要想在项目中使用 AutoMapper ,需要通过 nuget 引用 AutoMapperAutoMapper.Extensions.Microsoft.DependencyInjection 包,可以通过 Visual Studio 2019NuGet package manager 可视化界面安装 或者 通过 NuGet package manager 命令行工具输入以下命令:

Install-Package AutoMapper
Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection

配置 AutoMapper

一旦 AutoMapper 成功安装之后,接下来就可以将它引入到 ServiceCollection 容器中,如下代码所示:

public void ConfigureServices(IServiceCollection services)
{         
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    services.AddAutoMapper(typeof(AuthorProfile));
}

使用 profiles 统一管理 mapping 信息

可以使用 profiles 来统一组织你的 mapping 信息,要创建 profile,需要实现 AutoMapper 提供的 Profile 类,然后在你刚才创建的 Profile 子类的构造函数中添加映射信息,下面的代码展示了如何创建一个从 Proifle 继承的 AuthorProfile 类以及相关信息。

public class AuthorProfile : Profile
{
     public AuthorProfile()
     {
         CreateMap<AuthorModel, AuthorDTO>();
     }
}

接下来再看 AuthorModelAuthorDTO 两个对象的定义:

public class AuthorModel
{
    public int Id
    {
        get; set;
    }
    public string FirstName
    {
        get;set;
    }
    public string LastName
    {
        get; set;
    }
    public string Address
    {
        get; set;
    }
}

public class AuthorDTO
{
    public int Id
    {
        get; set;
    }
    public string FirstName
    {
        get; set;
    }
    public string LastName
    {
        get; set;
    }
    public string Address
    {
        get; set;
    }

使用 ReverseMap()

值得注意的是,上面的示例是一种 单向流动,这是什么意思呢?举个例子吧,下面是 单向流动 的一段代码。

AutoMapper.Mapper.CreateMap<AuthorDTO, AuthorModel>();

有了这个 Map,接下来就可以轻松实现 AuthorDTOAuthorModel 的转换,代码如下:

var authorModel = AutoMapper.Mapper.Map<AuthorModel>(author);

假设因为某种原因,你需要将 authorModel 实例反转成 authorDTO,这时你用了如下的代码段。

var author = AutoMapper.Mapper.Map<AuthorDTO>(authorModel);

很遗憾,这种方式注定会抛出异常,这是因为 AutoMapper 并不知道如何实现 authorModelauthorDTO 的转换,毕竟你没有定义此种 map 的映射流向,那怎么解决呢?可以再定义一个 CreateMap 映射哈,其实没必要,简单粗暴的做法就是调用 ReverseMap 即可,实现代码如下:

AutoMapper.Mapper.CreateMap<AuthorDTO, AuthorModel>().ReverseMap();

使用 ForMember()MapFrom()

这一节我们继续使用之前说到的 AuthorModelAuthorDTO 类,下面的代码片段展示了如何将 AuthorModel 转成 AuthorDTO

var author = new AuthorModel();           
author.Id = 1;
author.FirstName = "Joydip";
author.LastName = "Kanjilal";
author.Address = "Hyderabad";
var authorDTO = _mapper.Map<AuthorDTO>(author);

现在假设我将 AuthorModel 中的 Address 改成 Address1,如下代码所示:

   public class AuthorModel
   {
       public int Id
       {
           get; set;
       }
       public string FirstName
       {
           get; set;
       }
       public string LastName
       {
           get; set;
       }
       public string Address1
       {
           get; set;
       }
   }

然后在 AuthorProfile 中更新一下 mapping 信息,如下代码所示:

public class AuthorProfile : Profile
{
    public AuthorProfile()
    {
        CreateMap<AuthorModel, AuthorDTO>().ForMember(destination => destination.Address, map => map.MapFrom(source => source.Address1));
    }
}

使用 NullSubstitute

何为 NullSubstitute 呢?大意就是在映射转换的过程中,将inputnull 的属性映射之后做自定义处理,比如在 ouput 中改成 No Data,下面的代码展示了如何去实现。

AutoMapper.Mapper.CreateMap<AuthorModel, AuthorDTO>().ForMember(destination => destination.Address, opt => opt.NullSubstitute("No data"));

mapping 的 AOP 拦截

考虑下面的两个类。

  public class OrderModel
  {
    public int Id { get; set; }
    public string ItemCode { get; set; }
    public int NumberOfItems { get; set; }
  }

  public class OrderDTO
  {
    public int Id { get; set; }
    public string ItemCode { get; set; }
    public int NumberOfItems { get; set; }
  }

可以使用 BeforeMap() 在 源对象 或者 目标对象 上执行一些计算或者初始化成员操作,下面的代码展示了如何去实现。

Mapper.Initialize(cfg => {
  cfg.CreateMap().BeforeMap((src, dest) => src.NumberOfItems = 0)
});

mapping 执行完之后,可以在 目标对象 上 安插 AfterMap() 方法,下面的代码展示了如何去实现。

public OrderDTO MapAuthor(IMapper mapper, OrderDTO orderDTO)
{
    return mapper.Map<OrderModel, OrderDTO>(orderDTO, opt =>
    {
        opt.AfterMap((src, dest) =>
        {
            dest.NumberOfItems = _orderService.GetTotalItems(src);
       });
    });
}

使用嵌套映射

AutoMapper 同样也可以使用嵌套映射,考虑下面的 domain 类。

public class Order
{
    public string OrderNumber { get; set; }
    public IEnumerable<OrderItem> OrderItems { get; set; }
}

public class OrderItem
{
    public string ItemName { get; set; }
    public decimal ItemPrice { get; set; }
    public int ItemQuantity { get; set; }
}

接下来再看一下 DTO 类。

public class OrderDto
{
    public string OrderNumber { get; set; }
    public IEnumerable<OrderItemDto> OrderItems { get; set; }
}

public class OrderItemDto
{
    public string ItemName { get; set; }
    public decimal ItemPrice { get; set; }
    public int ItemQuantity { get; set; }
}

最后看看如何在转换的过程中使用 mapping 的。

var orders = _repository.GetOrders();
Mapper.CreateMap<Order, OrderDto>();
Mapper.CreateMap<OrderItem, OrderItemDto>();
var model = Mapper.Map<IEnumerable<Order>, IEnumerable<OrderDto>>(orders);

AutoMapper 让你用最小化的配置实现了对象之间的映射,同时也可以实现自定义的解析器来实现具有完全不同结构对象之间的映射,自定义解析器可以生成与目标对象具有相同结构的exchange,以便AutoMapper在运行时可以据其实现映射。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值