如何在 .NetCore 中使用 AutoMapper 高級功能
本文轉(zhuǎn)載自微信公眾號「碼農(nóng)讀書」,作者碼農(nóng)讀書。轉(zhuǎn)載本文請聯(lián)系碼農(nóng)讀書公眾號。
AutoMapper 是一個(gè)基于約定的面向?qū)ο蟮挠成淦?,它的功能常用于將一個(gè) input 對象 轉(zhuǎn)成一個(gè)不同類型的 output 對象,input 和 output 對象之間的屬性可能相同也可能不相同,這一篇我們來一起研究一下 AutoMapper 的一些高級玩法。
安裝 AutoMapper
要想在項(xiàng)目中使用 AutoMapper ,需要通過 nuget 引用 AutoMapper 和 AutoMapper.Extensions.Microsoft.DependencyInjection 包,可以通過 Visual Studio 2019 的 NuGet 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 統(tǒng)一管理 mapping 信息
可以使用 profiles 來統(tǒng)一組織你的 mapping 信息,要創(chuàng)建 profile,需要實(shí)現(xiàn) AutoMapper 提供的 Profile 類,然后在你剛才創(chuàng)建的 Profile 子類的構(gòu)造函數(shù)中添加映射信息,下面的代碼展示了如何創(chuàng)建一個(gè)從 Proifle 繼承的 AuthorProfile 類以及相關(guān)信息。
- public class AuthorProfile : Profile
- {
- public AuthorProfile()
- {
- CreateMap<AuthorModel, AuthorDTO>();
- }
- }
接下來再看 AuthorModel 和 AuthorDTO 兩個(gè)對象的定義:
- 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()
值得注意的是,上面的示例是一種 單向流動,這是什么意思呢?舉個(gè)例子吧,下面是 單向流動 的一段代碼。
- AutoMapper.Mapper.CreateMap<AuthorDTO, AuthorModel>();
有了這個(gè) Map,接下來就可以輕松實(shí)現(xiàn) AuthorDTO 到 AuthorModel 的轉(zhuǎn)換,代碼如下:
- var authorModel = AutoMapper.Mapper.Map<AuthorModel>(author);
假設(shè)因?yàn)槟撤N原因,你需要將 authorModel 實(shí)例反轉(zhuǎn)成 authorDTO,這時(shí)你用了如下的代碼段。
- var author = AutoMapper.Mapper.Map(authorModel);
很遺憾,這種方式注定會拋出異常,這是因?yàn)?AutoMapper 并不知道如何實(shí)現(xiàn) authorModel 到 authorDTO 的轉(zhuǎn)換,畢竟你沒有定義此種 map 的映射流向,那怎么解決呢?可以再定義一個(gè) CreateMap 映射哈,其實(shí)沒必要,簡單粗暴的做法就是調(diào)用 ReverseMap 即可,實(shí)現(xiàn)代碼如下:
- AutoMapper.Mapper.CreateMap<AuthorDTO, AuthorModel>().ReverseMap();
使用 ForMember() 和 MapFrom()
這一節(jié)我們繼續(xù)使用之前說到的 AuthorModel 和 AuthorDTO 類,下面的代碼片段展示了如何將 AuthorModel 轉(zhuǎn)成 AuthorDTO 。
- var author = new AuthorModel();
- author.Id = 1;
- author.FirstName = "Joydip";
- author.LastName = "Kanjilal";
- author.Address = "Hyderabad";
- var authorDTO = _mapper.Map<AuthorDTO>(author);
現(xiàn)在假設(shè)我將 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 呢?大意就是在映射轉(zhuǎn)換的過程中,將input 為null 的屬性映射之后做自定義處理,比如在 ouput 中改成 No Data,下面的代碼展示了如何去實(shí)現(xiàn)。
- AutoMapper.Mapper.CreateMap<AuthorModel, AuthorDTO>().ForMember(destination => destination.Address, opt => opt.NullSubstitute("No data"));
mapping 的 AOP 攔截
考慮下面的兩個(gè)類。
- 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() 在 源對象 或者 目標(biāo)對象 上執(zhí)行一些計(jì)算或者初始化成員操作,下面的代碼展示了如何去實(shí)現(xiàn)。
- Mapper.Initialize(cfg => {
- cfg.CreateMap().BeforeMap((src, dest) => src.NumberOfItems = 0)
- });
當(dāng) mapping 執(zhí)行完之后,可以在 目標(biāo)對象 上 安插 AfterMap() 方法,下面的代碼展示了如何去實(shí)現(xiàn)。
- 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; }
- }
最后看看如何在轉(zhuǎn)換的過程中使用 mapping 的。
- var orders = _repository.GetOrders();
- Mapper.CreateMap<Order, OrderDto>();
- Mapper.CreateMap<OrderItem, OrderItemDto>();
- var model = Mapper.Map<IEnumerable<Order>, IEnumerable<OrderDto>>(orders);
AutoMapper 讓你用最小化的配置實(shí)現(xiàn)了對象之間的映射,同時(shí)也可以實(shí)現(xiàn)自定義的解析器來實(shí)現(xiàn)具有完全不同結(jié)構(gòu)對象之間的映射,自定義解析器可以生成與目標(biāo)對象具有相同結(jié)構(gòu)的exchange,以便AutoMapper在運(yùn)行時(shí)可以據(jù)其實(shí)現(xiàn)映射。
譯文鏈接:https://www.infoworld.com/article/3406800/more-advanced-automapper-examples-in-net-core.html