在ABP中靈活使用AutoMapper

demo地址:ABP.WindowsService
該文章是系列文章 基於.NetCore和ABP框架如何讓Windows服務執行Quartz定時作業 的其中一篇。

AutoMapper簡介

AutoMapper是一個簡單的小型的對象映射庫,是爲了解決一個繁雜的問題 - 將一個對象映射到另一個對象的到處亂飛的膠水代碼。這類膠水代碼非常沉悶,讓人懷疑自己的工作的價值性。AutoMapper就是你擺脫此類代碼的福音。
官網地址:https://automapper.org/
GitHub地址:https://github.com/AutoMapper/AutoMapper

AutoMapper的簡單使用

這裏拿官網的例子做一個簡單說明,主要是爲了引出在Abp中是如何使用的,來進行對比。使用AutoMapper將遇到的最經典的兩個場景。

  1. 最多遇到的場景,應該是接口返回的DTO和數據庫Entity,出於敏感信息保護或者減少接口返回數據等等的原因,DTO返回的屬性或者字段有所刪減,也就是說需要映射的屬性或者字段屬性名稱一致。
  2. DTO和Entity名稱不一致,甚至類型不同,相互轉換時甚至需要對數據有處理。

下面的例子就是字段屬性基本一致。

public class Order
{
        public string OrderName { get;set; }
        public string PhoneNumber { get;set; }
}
public class OrderDto
{
        public string OrderName { get;set; }
}
var config = new MapperConfiguration(cfg => cfg.CreateMap<Order, OrderDto>());
var mapper = config.CreateMapper();
OrderDto dto = mapper.Map<OrderDto>(order);

或者

var config = new MapperConfiguration(cfg => cfg.CreateMap<Order, OrderDto>());
var mapper = new Mapper(config);
OrderDto dto = mapper.Map<OrderDto>(order);

Abp.AutoMapper的簡單使用

Abp.AutoMapper的官網文檔:https://aspnetboilerplate.com/Pages/Documents/Object-To-Object-Mapping
Abp.AutoMapper的Nuget地址:https://www.nuget.org/packages/Abp.AutoMapper

添加nuget包

Install-Package Abp.AutoMapper

添加AbpAutoMapperModule模塊

[DependsOn(typeof(AbpAutoMapperModule))]
public class MyJobCoreModule : AbpModule
{
}

指定映射關係

自動映射

你可以通過屬性AutoMap, AutoMapFrom, AutoMapTo指定映射關係
改造上面的之前的例子

[AutoMapFrom(typeof(Order))]
public class OrderDto
{
        public string OrderName { get;set; }
}

或者

[AutoMapTo(typeof(OrderDto))]
public class Order
{
        public string OrderName { get;set; }
        public string PhoneNumber { get;set; }
}

但是屬性的使用場景比較窄,稍微複雜一點的場景就無法滿足,比如,指定忽略一些字段,或者字段名稱不同需要顯示指定。

自定義映射

[DependsOn(typeof(AbpAutoMapperModule))]
public class MyJobCoreModule : AbpModule
{
    public override void PreInitialize()
    {
        Configuration.Modules.AbpAutoMapper().Configurators.Add(config =>
        {
            config.CreateMap<Order, OrderDto>();
        });
    }
}

忽略字段

config.CreateMap<Order, OrderDto>()
          .ForMember(u => u.PhoneNumber, options => options.Ignore());

字段名不一致

OrderDto增加手機號字段Tel,映射Order字段PhoneNumber

    public class OrderDto
    {
        public string OrderName { get; set; }
        public string Tel { get; set; }
    }
config.CreateMap<Order, OrderDto>()
          .ForMember(u => u.Tel, options => options.MapFrom(input => input.PhoneNumber));

需要對字段進行處理後返回

比如,隱藏11位手機號的中間4位

private static string HideTel(string input)
{
    if (string.IsNullOrEmpty(input))
    {
        return string.Empty;
    }
    var outReplace = Regex.Replace(input, "(\\d{3})\\d{4}(\\d{4})", "$1****$2");
    return outReplace;
}
config.CreateMap<Order, OrderDto>()
          .ForMember(u => u.Tel, options => options.MapFrom(input => HideTel(input.PhoneNumber)));

拼接映射

又比如OrderDto新增郵寄地址和收貨地址

namespace Demo.MyJob.Entity.Dto
{
    public class OrderDto
    {
        public string OrderName { get; set; }
        public string Tel { get; set; }
        public string PostalAddress { get; set; }
        public string DeliveryAddress { get; set; }
    }
}

Order的相關表OrderAddress類型定義

namespace Demo.MyJob.Entity
{
    public class OrderAddress
    {
        public string OrderId { get; set; }
        public string PostalAddress { get; set; }
        public string DeliveryAddress { get; set; }
    }
}

這時就需要OrderAddress和Order的數據相結合映射OrderDto,怎麼實現呢?藉助元組Tuple。

config.CreateMap<(Order, OrderAddress), OrderDto>()
          .ForMember(u => u.Tel, options => options.MapFrom(input => HideTel(input.Item1.PhoneNumber)))
          .ForMember(u => u.OrderName, options => options.MapFrom(input => input.Item1.OrderName))
          .ForMember(u => u.PostalAddress, options => options.MapFrom(input => input.Item2.PostalAddress))
          .ForMember(u => u.DeliveryAddress, options => options.MapFrom(input => input.Item2.DeliveryAddress))
          ;

精簡配置

需要自定義的映射關係過多時,會使得PreInitialize變大,不便於管理和查看。

public override void PreInitialize()
{
    Configuration.Modules.AbpAutoMapper().Configurators.Add(config =>
    {
        config.CreateMap<(Order, OrderAddress), OrderDto>()
          .ForMember(u => u.Tel, options => options.MapFrom(input => HideTel(input.Item1.PhoneNumber)))
          .ForMember(u => u.OrderName, options => options.MapFrom(input => input.Item1.OrderName))
          .ForMember(u => u.PostalAddress, options => options.MapFrom(input => input.Item2.PostalAddress))
          .ForMember(u => u.DeliveryAddress, options => options.MapFrom(input => input.Item2.DeliveryAddress))
          ;
    });
}

如何精簡?新增類型MyMapperProfile,繼承AutoMapper.Profile

using System.Text.RegularExpressions;
using AutoMapper;
using Demo.MyJob.Entity;
using Demo.MyJob.Entity.Dto;

namespace Demo.MyJob.MapperProfiles
{
    class MyMapperProfile : Profile
    {
        private static string HideTel(string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                return string.Empty;
            }
            var outReplace = Regex.Replace(input, "(\\d{3})\\d{4}(\\d{4})", "$1****$2");
            return outReplace;
        }
        public MyMapperProfile()
        {
            CreateMap<Order, OrderDto>()
                .ForMember(u => u.Tel, options => options.MapFrom(input => HideTel(input.PhoneNumber)));

            CreateMap<(Order, OrderAddress), OrderDto>()
                .ForMember(u => u.Tel, options => options.MapFrom(input => HideTel(input.Item1.PhoneNumber)))
                .ForMember(u => u.OrderName, options => options.MapFrom(input => input.Item1.OrderName))
                .ForMember(u => u.PostalAddress, options => options.MapFrom(input => input.Item2.PostalAddress))
                .ForMember(u => u.DeliveryAddress, options => options.MapFrom(input => input.Item2.DeliveryAddress))
                ;
        }
    }
}

修改PreInitialize

[DependsOn(typeof(AbpAutoMapperModule))]
public class MyJobCoreModule : AbpModule
{
    public override void PreInitialize()
    {
        Configuration.Modules.AbpAutoMapper().Configurators.Add(config =>
        {
            config.AddMaps(typeof(MyJobCoreModule));
        });
    }
}

Abp.AutoMapper版本低於4.8.0的可以修改爲

config.AddProfiles(typeof(MyJobCoreModule));

以上就是如何在Abp框架下靈活使用AutoMapper的全部內容,謝謝閱讀。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章