对象映射工具AutoMapper介绍
AutoMapper是用來解決對(duì)象之間映射轉(zhuǎn)換的類庫(kù)。對(duì)于我們開發(fā)人員來說,寫對(duì)象之間互相轉(zhuǎn)換的代碼是一件極其浪費(fèi)生命的事情,AutoMapper能夠幫助我們節(jié)省不少時(shí)間。
一. AutoMapper解決了什么問題?
要問AutoMapper解決了什么問題? 難道不是對(duì)象映射轉(zhuǎn)換的問題嗎??
當(dāng)然是,不過我們可以問深入一些,為什么項(xiàng)目中會(huì)出現(xiàn)大量的對(duì)象映射轉(zhuǎn)換?(以下對(duì)于非MVC項(xiàng)目也適用)
在現(xiàn)代的軟件開發(fā)中,項(xiàng)目的層級(jí)更加的細(xì)分,而不同層級(jí)之間對(duì)于對(duì)象的需求是有區(qū)別的,這就需要在不同層級(jí)間傳遞數(shù)據(jù)的時(shí)候,必須要轉(zhuǎn)換數(shù)據(jù)。
舉一些實(shí)際具體的例子:
在持久層(數(shù)據(jù)訪問層), 我們的User對(duì)象,可能是一個(gè)包含User表中所有字段的數(shù)據(jù)的對(duì)象,甚至包含了用戶的Password信息。而在界面層,我們只是需要顯示用戶的 name, email,不需要Password這些額外的信息,同時(shí),它還需要用戶的考勤信息,而這個(gè)信息來自于另外一張表。?
這個(gè)例子中,能夠發(fā)現(xiàn)不同層之間,我們對(duì)于數(shù)據(jù)對(duì)象的需求是不同的。?
每個(gè)層都做了它們職責(zé)范圍內(nèi)的事情:?
持久層關(guān)注數(shù)據(jù),所以只提供數(shù)據(jù)對(duì)象,它無需知道外層如何使用這些數(shù)據(jù)對(duì)象,也無法知道。?
界面層關(guān)注數(shù)據(jù)的呈現(xiàn),它只關(guān)注它要顯示的數(shù)據(jù)。
那么問題是,誰來彌補(bǔ)它們之間的鴻溝?DTO(Data Transfer Object)——數(shù)據(jù)傳輸對(duì)象。而AutoMapper就是解決其中涉及到的數(shù)據(jù)對(duì)象轉(zhuǎn)換的工具。
在實(shí)際開發(fā)中,如果你還可以直接在Business層或者界面層直接使用持久層的對(duì)象,因?yàn)槟阏J(rèn)為這個(gè)關(guān)系不大,整個(gè)項(xiàng)目都是你自己控制的,雖然 dirty,但是quick. 作為一個(gè)有些潔癖的程序員,我還是建議使用DTO在不同層級(jí)之間傳遞數(shù)據(jù)。因?yàn)楫?dāng)你做更高層級(jí)開發(fā)的時(shí)候,比如開發(fā)web service,WCF,Web API這些為系統(tǒng)外部提供接口的開發(fā)時(shí)候,你就回明白這些好的習(xí)慣和思維能夠幫助你更加好的設(shè)計(jì)這些外部接口。
二. AutoMapper如何使用?
先來看一個(gè)簡(jiǎn)單的例子,這個(gè)例子是定義Order對(duì)象到OrderDto對(duì)象之間的映射。(我們把Order稱呼為源類,OrderDto稱呼為目標(biāo)類)
Mapper.CreateMap<Order, OrderDto>();//創(chuàng)建映射關(guān)系Order –> OrderDto OrderDto dto = Mapper.Map<OrderDto>(order);//使用Map方法,直接將order對(duì)象裝換成OrderDto對(duì)象智能匹配
AutoMapper能夠自動(dòng)識(shí)別和匹配大部分對(duì)象屬性:
- 如果源類和目標(biāo)類的屬性名稱相同,直接匹配
 - 目標(biāo)類型的CustomerName可以匹配源類型的Customer.Name
 - 目標(biāo)類型的Total可以匹配源類型的GetTotal()方法
 
自定義匹配規(guī)則
AutoMapper還支持自定義匹配規(guī)則
Mapper.CreateMap<CalendarEvent, CalendarEventForm>() //屬性匹配,匹配源類中WorkEvent.Date到EventDate.ForMember(dest => dest.EventDate, opt => opt.MapFrom(src => src.WorkEvent.Date)).ForMember(dest => dest.SomeValue, opt => opt.Ignore())//忽略目標(biāo)類中的屬性.ForMember(dest => dest.TotalAmount, opt => opt.MapFrom(src => src.TotalAmount ?? 0))//復(fù)雜的匹配.ForMember(dest => dest.OrderDate, opt => opt.UserValue<DateTime>(DateTime.Now));固定值匹配測(cè)試
當(dāng)定義完規(guī)則后,可以使用下面的代碼來驗(yàn)證配置是否正確。不正確拋出異常AutoMapperConfigurationException.
三. AutoMapper處理多對(duì)一映射
我們開篇提到的問題中,說到界面顯示User的name, email, 還有用戶的考勤信息,而這些信息來自于2張不同的表。這就涉及到了多對(duì)一映射的問題,2個(gè)持久層對(duì)象需要映射到一個(gè)界面顯示層的對(duì)象。
假設(shè)我們的持久層對(duì)象是這樣的:
public class User {public int Id { get; set; }public string Name { get; set; }public string Email { get; set; }public string Passworkd { get; set; }public DateTime Birthday { get; set; } }public class Evaluation {public int Id { get; set; }public int Score { get; set; } }在Asp.net MVC中,我的界面顯示層的ViewModel是這樣的 public class UserViewModel {public int Id { get; set; }public string Name { get; set; }public string Email { get; set; }public int Score { get; set; } }
接下來,為了達(dá)到多對(duì)一的映射的目的,我們創(chuàng)建這個(gè)EntityMapper類
public static class EntityMapper {public static T Map<T>(params object[] sources) where T : class{if (!sources.Any()){return default(T);}var initialSource = sources[0];var mappingResult = Map<T>(initialSource);// Now map the remaining source objectsif (sources.Count() > 1){Map(mappingResult, sources.Skip(1).ToArray());}return mappingResult;}private static void Map(object destination, params object[] sources){if (!sources.Any()){return;}var destinationType = destination.GetType();foreach (var source in sources){var sourceType = source.GetType();Mapper.Map(source, destination, sourceType, destinationType);}}private static T Map<T>(object source) where T : class{var destinationType = typeof(T);var sourceType = source.GetType();var mappingResult = Mapper.Map(source, sourceType, destinationType);return mappingResult as T;}}為了實(shí)現(xiàn)多個(gè)源對(duì)象映射一個(gè)目標(biāo)對(duì)象,我們使用了AutoMapper的方法,從不同的源對(duì)象逐一匹配一個(gè)已經(jīng)存在的目標(biāo)對(duì)象。下面是實(shí)際使用在MVC中的代碼:
public ActionResult Index() {var userId = 23,var user = _userRepository.Get(userId);var score = _scoreRepository.GetScore(userId);var userViewModel = EntityMapper.Map<UserViewModel>(user, score);return this.View(userViewModel); }四. 使用Profile在Asp.net MVC項(xiàng)目中配置AutoMapper
Profile是AutoMapper中用來分離類型映射定義的,這樣可以讓我們的定義AutoMapper類型匹配的代碼可以更加分散,合理和易于管理。
利用Profile, 我們可以更加優(yōu)雅的在MVC項(xiàng)目中使用我們的AutoMapper. 下面是具體的方法:
1.??在不同層中定義Profile,只定義本層中的類型映射
繼承AutoMapping的Profile類,重寫ProfileName屬性和Configure()方法。
public class ViewModelMappingProfile: Profile {public override string ProfileName{get{return GetType().Name;}}protected override void Configure(){Mapper.CreateMap......} }2.?創(chuàng)建AutoMapperConfiguration,?提供靜態(tài)方法Configure,一次加載所有層中Profile定義
public class AutoMapperConfiguration {public static void Configure(){Mapper.Initialize(x => x.AddProfile<ViewModelMappingProfile>());Mapper.AssertConfigurationIsValid();} }3.?在Global.cs文件中執(zhí)行
最后,在Global.cs文件中程序啟動(dòng)前,調(diào)用該方法
AutoMapperConfiguration.Configuration()轉(zhuǎn)載于:https://www.cnblogs.com/hnsongbiao/p/8732627.html
總結(jié)
以上是生活随笔為你收集整理的对象映射工具AutoMapper介绍的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: php设计模式-工厂设计模式
 - 下一篇: 梦到花是胎梦吗