AutoMapper入门使用
AutoMapper入門使用
在應用開發的過程中,首先要了解整個系統中各個系統的組件的作用,然后了解系統的工作流(workflow),最后需要梳理一遍數據流(dataflow),而在整理數據流的過程中,數據的轉化常常是最難理解寫起來相當枯燥乏味的部分,AutoMapper的功能就是實現映射一個對象到另一個對象的自動化工具,最常見的就是DTO (Data Transfer Object)與MO(ModelObject)之間的轉換,這里我先介紹一下DTO與MO的關系,然后才介紹AutoMapper工具的使用。
理解DTO
以下是我總結的幾個不同平臺的解釋:
- 百度百科:
數據傳輸對象(DTO)(Data Transfer Object),是一種設計模式之間傳輸數據的軟件應用系統。數據傳輸目標往往是數據訪問對象從數據庫中檢索數據。數據傳輸對象與數據交互對象或數據訪問對象之間的差異是一個以不具有任何行為除了存儲和檢索的數據(訪問和存取器)
- 維基百科:
數據傳輸對象(DTO)是在兩個進程之間承載數據的對象。數據傳輸和業務對象或數據訪問對象之間的區別在于,DTO除了存儲和檢索其自身的數據(調制器和訪問器)之外沒有任何行為。DTO是不應該包含任何需要測試的業務邏輯的簡單對象。
- 博客園dax.net:
表現層于應用層之間是通過DTO來進行交互的,數據傳輸對象是沒有行為的POCO對象,他的目的是為了對領域對象進行數據封裝,實現層與層之間的數據傳遞。簡單來說Model面向業務,我們是通過業務來定義Model的。而DTO是面向UI,通過UI的需求來定義的,通過DTO我們實現了表現層與Model層之間的解耦,表現層不引用Model。如果開發過程中我們的模型變了,而界面沒變,我們只需改Model而不需要去改動表現層。
看了這些解釋,應該還是有點蒙?
先來看看為什么要使用DTO,我總結了三點
- 隔離領域模型,使用封裝(包括數據結構的精簡和合并)的DTO實現改動領域模型而不影響UI,保持領域模型的安全,不暴露業務邏輯。
- 在分布式模式下,相同的數據結構在不同的場景使用相同的數據結構有不同的需求。
- DTO的存在也為了幫助減少客戶端請求而降低服務器壓力,提升效率。
不是所有的時候都需要用到DTO,如果為所有的不同需求都建一個DTO,那么一個概念所對應的DTO可能多達5,6種,非常難于管理,當頁面所需要的數據與數據庫中的數據不一致的情況如果常常出現,那么我們就需要開始著手準備添加對DTO的支持,并且DTO可以設當的冗余設計來減少DTO種類
在系統中添加DTO主要有以下幾部分工作需要完成
- 設計和添加DTO類。
- 添加從MO到DTO的轉化邏輯。
- 將原本對MO的使用轉換為對DTO的使用。(這里可以看出,要盡早的預判是否需要DTO,以免將來麻煩)
關于DTO就了解到這,下面開始回歸正題,介紹AutoMapper工具的使用
AutoMapper入門
安裝AutoMapper
- 從包管理器控制臺安裝
打開程序包管理器控制臺,然后輸入命令:Install-Package?AutoMapper
- 從包管理器界面安裝
在界面中搜索需要安裝的程序集,如AutoMapper.dll
安裝完成之后添加到程序集引用中即可。
如何使用AutoMapper
首先,您需要使用源類型和目標類型。目標類型的設計可能受其所在層的影響,但只要成員的名稱與源類型的成員匹配,AutoMapper就可以發揮最佳效果。如果您有一個名為“FirstName”的源成員,它將自動映射到名稱為“FirstName”的目標成員。AutoMapper也支持拼合。
一旦你有了你的類型,你可以使用MapperConfiguration或者靜態Mapper實例和CreateMap為這兩種類型創建一個映射。MapperConfiguration通常每個AppDomain只需要一個實例,并且應該在啟動過程中實例化。
- 創建映射的兩種方式(左側的類型是源類型,右側的類型是目標類型):
- 靜態方式:
- Mapper.Initialize(cfg?=>?cfg.CreateMap<Order,?OrderDto>());
- 如果您使用的是靜態Mapper方法,則每個AppDomain只能進行一次配置。這意味著放置配置代碼的最佳位置是在應用程序啟動時,例如ASP.NET應用程序的Global.asax文件
- 實例方式
- var?config?= new?MapperConfiguration(cfg?=>?cfg.CreateMap<Order,?OrderDto>());
要執行映射又可以使用靜態或實例映射器方法:
- IMapper?mapper =?config.CreateMapper();
- IMapper?mapper = new Mapper(config);
大多數應用程序可以使用依賴注入來注入創建的IMapper實例。
- 可以添加配置到配置類中,方便統一管理(AddProfile),然后通過自己寫一下泛型返回自己想要的類型轉換,這樣可以一次性實例化多種類型映射:
- Mapper.Initialize(cfg?=>?cfg.AddProfile(new?MyProfile()));
- Mapper.Initialize(cfg?=>?cfg.AddProfile<MyProfile>());
- var?config?= new?MapperConfiguration(fig =>?fig.AddProfile(new?MyProfile()));
- var?config?= new?MapperConfiguration(fig =>?fig.AddProfile<?MyProfile>());
處理下面幾種情況的方式
屬性名稱相同
扁平化映射
投影(指定字段)
簡單類型映射
使用Profile配置
屬性名稱不同
條件映射:
空值替換NullSubstitute
忽略屬性Ignore
目標屬性多于源屬性,可以進行預設值
類型轉換ITypeConverter
?
using?AutoMapper;
using?System;
using?System.Collections.Generic;
using?System.Linq;
using?System.Text;
using?System.Threading.Tasks;
?
namespace?AutoMapperDemo
{
? ?public?static?class?AutoMapperInitialize
? ?{
? ? ? ?static?AutoMapperInitialize()
? ? ? ?{
? ? ? ? ? ?Mapper.Initialize(fig =>?fig.AddProfile<MyProfile>());
? ? ? ?}
? ? ? ?public?class?User
? ? ? ?{
? ? ? ? ? ?public?int?Id {?set;?get; }
? ? ? ? ? ?public?string?Name {?set;?get; }
? ? ? ? ? ?public?int?Age {?set;?get; }
? ? ? ? ? ?public?User(int?i)
? ? ? ? ? ?{
? ? ? ? ? ? ? ?Id =?i;
? ? ? ? ? ? ? ?Name =?"muphy-"?+?i;
? ? ? ? ? ? ? ?Age = 15 +?i;
? ? ? ? ? ?}
? ? ? ? ? ?public?User()
? ? ? ? ? ?{
? ? ? ? ? ? ? ?Id = 1;
? ? ? ? ? ? ? ?Name =?"muphy";
? ? ? ? ? ? ? ?Age = 15;
? ? ? ? ? ?}
? ? ? ? ? ?public?override?string?ToString()
? ? ? ? ? ?{
? ? ? ? ? ? ? ?return?"[Name:"?+ Name +?",Age:"?+ Age +?"]";
? ? ? ? ? ?}
? ? ? ?}
?
? ? ? ?public?class?UserDto
? ? ? ?{
? ? ? ? ? ?public?string?Name {?set;?get; }
? ? ? ? ? ?public?int?Age {?set;?get; }
?
? ? ? ? ? ?public?override?string?ToString()
? ? ? ? ? ?{
? ? ? ? ? ? ? ?return?"[Name:"?+ Name +?",Age:"?+ Age +?"]";
? ? ? ? ? ?}
? ? ? ?}
?
? ? ? ?public?class?Azi?:?User
? ? ? ?{
? ? ? ? ? ?public?string?Like {?set;?get; }
? ? ? ? ? ?public?Azi(int?i) :?base(i) { Like =?"QiaoFeng"; }
? ? ? ? ? ?public?Azi() { }
? ? ? ? ? ?public?override?string?ToString()
? ? ? ? ? ?{
? ? ? ? ? ? ? ?return?"[Name:"?+ Name +?",Age:"?+ Age +?"]";
? ? ? ? ? ?}
? ? ? ?}
?
? ? ? ?public?class?Product
? ? ? ?{
? ? ? ? ? ?public?Supplier?Supplier?{?set;?get; }
? ? ? ? ? ?public?decimal?GetPrice()
? ? ? ? ? ?{
? ? ? ? ? ? ? ?return?10;
? ? ? ? ? ?}
?
? ? ? ? ? ?public?Product()
? ? ? ? ? ?{
? ? ? ? ? ? ? ?Supplier =?new?Supplier();
? ? ? ? ? ?}
? ? ? ?}
? ? ? ?public?class?Supplier
? ? ? ?{
? ? ? ? ? ?public?string?Name {?get;?set; }
? ? ? ? ? ?public?Supplier()
? ? ? ? ? ?{
? ? ? ? ? ? ? ?Name =?"偉創力";
? ? ? ? ? ?}
? ? ? ?}
? ? ? ?public?class?ProductDto
? ? ? ?{
? ? ? ? ? ?public?string?SupplierName?{?set;?get; }
? ? ? ? ? ?public?decimal?Price {?set;?get; }
? ? ? ? ? ?public?override?string?ToString()
? ? ? ? ? ?{
? ? ? ? ? ? ? ?return?"[Price:"?+ Price +?",SupplierName:"?+?SupplierName?+?"]";
? ? ? ? ? ?}
? ? ? ?}
?
? ? ? ?public?class?Book?:?Product
? ? ? ?{
? ? ? ? ? ?public?DateTime?BuyTime?{?get?{?return?DateTime.Now; } }
? ? ? ?}
?
? ? ? ?public?class?BookDto?:?ProductDto
? ? ? ?{
? ? ? ? ? ?public?DateTime?Date {?get;?set; }
? ? ? ? ? ?public?int?Hour {?get;?set; }
? ? ? ? ? ?public?int?Minute {?get;?set; }
? ? ? ? ? ?public?override?string?ToString()
? ? ? ? ? ?{
? ? ? ? ? ? ? ?return?"[Price:"?+ Price +?",SupplierName:"?+?SupplierName?+?",Date:"?+ Date +?"]";
? ? ? ? ? ?}
? ? ? ?}
?
? ? ? ?public?class?Source
? ? ? ?{
? ? ? ? ? ?public?string?Name {?get?{?return?"muphy"; } }
? ? ? ? ? ?public?int?Width {?set;?get; }
? ? ? ?}
?
? ? ? ?public?class?Destination
? ? ? ?{
? ? ? ? ? ?public?string?Name {?get;?set; }
? ? ? ? ? ?public?string?like {?get;?set; }
?
? ? ? ? ? ?public?override?string?ToString()
? ? ? ? ? ?{
? ? ? ? ? ? ? ?return?Name +?" Like "?+ like;
? ? ? ? ? ?}
? ? ? ?}
?
? ? ? ?public?class?MyProfile?:?Profile
? ? ? ?{
? ? ? ? ? ?public?MyProfile()
? ? ? ? ? ?{
? ? ? ? ? ? ? ?//類型字段系統
? ? ? ? ? ? ? ?CreateMap<User,?UserDto>();
? ? ? ? ? ? ? ?//扁平化映射
? ? ? ? ? ? ? ?CreateMap<Product,?ProductDto>();
? ? ? ? ? ? ? ?//投影
? ? ? ? ? ? ? ?CreateMap<Book,?BookDto>()
? ? ? ? ? ? ? ? ? ?.ForMember(desc?=>?desc.Date, opt =>?opt.MapFrom(src?=>?src.BuyTime.Date))
? ? ? ? ? ? ? ? ? ?.ForMember(desc?=>?desc.Hour, opt =>?opt.MapFrom(src?=>?src.BuyTime.Hour))
? ? ? ? ? ? ? ? ? ?.ForMember(desc?=>?desc.Minute, opt =>?opt.MapFrom(src?=>?src.BuyTime.Minute));
? ? ? ? ? ? ? ?//?條件映射
? ? ? ? ? ? ? ?CreateMap<Azi,?UserDto>().ForMember(desc?=>?desc.Age, opt =>?opt.MapFrom(src?=>?src.Age< 21));
?
? ? ? ? ? ? ? ?//?可設置默認值
? ? ? ? ? ? ? ?CreateMap<Source,?Destination>().ForMember(desc?=>?desc.like, opt =>?opt.MapFrom(src?=>"azi"));
?
? ? ? ? ? ? ? ?//可忽視多余值
? ? ? ? ? ? ? ?CreateMap<?Destination,?Source>().ForMember(desc?=>?desc.Width, opt =>?opt.Ignore());
?
? ? ? ? ? ? ? ?//空值替換
? ? ? ? ? ? ? ?CreateMap<Source,?Destination>().ForMember(desc?=>?desc.Name, opt =>opt.NullSubstitute("azi"));
?
? ? ? ? ? ? ? ?//其他設置
? ? ? ? ? ? ? ?CreateMap<User,?Azi>()
? ? ? ? ? ? ? ? ? ?.BeforeMap((src,desc) =>?src.Age?+= 50)
? ? ? ? ? ? ? ? ? ?.AfterMap((src,desc)=>desc.Age?-= ?35)//?設置轉換前后的行為
? ? ? ? ? ? ? ? ? ?.ReverseMap();//設置反向映射
? ? ? ? ? ?}
? ? ? ?}
?
? ? ? ?// 1.簡單靜態的方式初始化映射?使用Initialize?兩個方法:CreateMap?AddProfile(稍后)
? ? ? ?public?static?UserDto?AutoMapperConfig1()
? ? ? ?{
? ? ? ? ? ?//Mapper.Initialize(cfg?=>?cfg.CreateMap<User,?UserDto>());
? ? ? ? ? ?//Mapper.Initialize(cfg?=>?cfg.AddProfile(new?MyProfile()));
? ? ? ? ? ?//Mapper.Initialize(cfg?=>?cfg.AddProfile<MyProfile>());
? ? ? ? ? ?UserDto?dto?=?Mapper.Map<UserDto>(new?User(1));
? ? ? ? ? ?return?dto;
? ? ? ?}
?
? ? ? ?// 2.簡單實例的方式初始化方式映射?使用MapperConfiguration??也有兩種方式:CreateMapper方法和Mpapper構造函數
? ? ? ?public?static?UserDto?AutoMapperConfig2()
? ? ? ?{
? ? ? ? ? ?MapperConfiguration?config?=?new?MapperConfiguration(fig =>?fig.CreateMap<User,?UserDto>());
? ? ? ? ? ?var?mapper =?config.CreateMapper();
? ? ? ? ? ?//IMapper?mapper = new?Mapper(config);
? ? ? ? ? ?return?mapper.Map<UserDto>(new?User(2));
? ? ? ?}
?
? ? ? ?// 3.使用繼承Profile的配置屬性方式映射?AddProfile方法
? ? ? ?public?static?UserDto?AutoMapperConfig3()
? ? ? ?{
? ? ? ? ? ?MapperConfiguration?config?=?new?MapperConfiguration(fig =>?fig.AddProfile<MyProfile>());
? ? ? ? ? ?IMapper?mapper =?new?Mapper(config);
? ? ? ? ? ?return?mapper.Map<UserDto>(new?User(3));
? ? ? ?}
?
?
? ? ? ?// 4.使用繼承Profile的配置屬性?+?泛型方式映射?效果會更好
? ? ? ?public?static?T?AutoMapperConfig4<K,?T>(K?k)
? ? ? ?{
? ? ? ? ? ?return?Mapper.Map<T>(k);
? ? ? ?}
?
?
? ? ? ?// 5.扁平化映射
? ? ? ?public?static?ProductDto?AutoMapperConfig5()
? ? ? ?{
? ? ? ? ? ?MapperConfiguration?config?=?new?MapperConfiguration(fig =>?fig.AddProfile<MyProfile>());
? ? ? ? ? ?var?mapper =?config.CreateMapper();
? ? ? ? ? ?return?mapper.Map<ProductDto>(new?Product());
? ? ? ?}
?
? ?}
?
}
轉載于:https://www.cnblogs.com/muphy/p/10781458.html
總結
以上是生活随笔為你收集整理的AutoMapper入门使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 你也被Spring的这个“线程池”坑过吗
- 下一篇: 一个IT时代的终结:109岁的IBM将分