近日在做項目的時候,遇到了個怪問題,關於AutoMapper的細節問題,也是不為一般人所關注的。
本人研究AutoMapper也沒有多長時間,而且研究的過程中也寫了關於AutoMapper的系列基礎教程,但是畢竟AutoMapper是個開源項目,並不是一個簡單的系列教程就能解釋的清楚的,只能解釋個大概,項目實戰的時候,遇到的細節問題還得自己私下里再次研究、總結。
首先,我要說明的是,這篇博客的寫作順序是按事情發展的順序來寫的,也就是說,在我想寫這篇博客時,問題的根本原因還沒找到,但是此時,我回過頭來,再來看這個過程中每個問題的解決思路,我想,此時這個細節的問題已經清楚了,也來分享一下。
先來讓大家看看我的AutoMapper的大致配置過程:
- 先創建實體類對應的AutoMapper配置類,命名規范是EntityName(實體類名)+Profile,比如PersonProfile,ProvincePerfile等。
public class ProvinceProfile : Profile { protected override void Configure() { Mapper.Initialize(cfg => cfg.CreateMap<Provinces, ProvinceDto>() .ForSourceMember(src=>src.UpdatedDate,opt=>opt.Ignore()) .ReverseMap()); } }
- 再創建一個靜態類,取名AutoMapperConfig,然后在他的靜態方法中初始化Mapper,並添加所有的配置類,這里我還添加了其他配置類。
public static class AutoMapperWebConfig { public static void Configure() { Mapper.Reset(); Mapper.Initialize(cfg => { cfg.AddProfile<ProvinceProfile>(); cfg.AddProfile<CityProfile>(); cfg.AddProfile<StationProfile>(); cfg.AddProfile<TerminalDeviceProfile>();//TerminalDeviceProfile依賴ProvinceProfile cfg.AddProfile<OperatorProfile>(); }); Mapper.AssertConfigurationIsValid();//驗證所有的映射配置是否都正常 } }
- 最后,在項目啟動的時候(ASP.Net程序在.asax文件中的Application_Start方法)調用AutoMapperWebConfig.Configure();就可以了。
這一切都感覺這么順利,但是往往越是順利的時候,也意味着不順快來了。接下來,類似下面截圖中的錯誤向我狂轟亂炸。
當我使用在應用層使用Mapper.Map()方法將實體類映射為Dto類時,報錯如下:
很明顯這是AutoMapper映射錯誤。
接下來就各種搜索錯誤,找到了下面一篇博客,原文
ta的解決方案是,如圖
看到這里,我很高興,趕緊改了一下自己的代碼,發現果然成功了!但是該博主並沒有給出個所以然來。
但是,我不服氣,我之前已經創建了兩個類之間的映射啊,為啥Mapper.Map()方法不行,我就納悶了,我非得搞清楚這兩者之間的關系不可。
我尋思着,就字面意思來看,一個是“映射”,一個是“動態映射”,會有啥區別呢?
於是各種搜兩者之間的區別,去StackOverflow上找到了下面的答案:原鏈接
這里說,DynamicMap在編譯時你不知道源類型的情況下使用,那么,相應地,Map就是在編譯時知道源類型的情況下使用。簡單的這一句解釋並不能讓接觸AutoMapper時間不長的人有所啟示。
而問題就出在,我之前已經創建了映射,所以在編譯時應該可以確定源類型的,更何況我這兩個類都很簡單,不可能是因為數據類型不一致造成的映射失敗啊!代碼如下:
public class Provinces : Entity { public virtual string Code{ get; set; } public virtual string Name{ get; set; } public virtual string UpdatedBy{ get; set; } public virtual DateTime? UpdatedDate{ get; set; } public Provinces(){} }
public class ProvinceDto:EntityDto { public string Code { get; set; } public string Name { get; set; } }
於是,還得不到自己想要的答案,就去GitHub上AutoMapper的項目下Open了一個Issue,點擊查看我提的Issue,在這里,我得到了我想要的答案。
該回答者給我的答案如上,他猜想我在每個實體類對應的Profile文件中,應該直接使用CreateMap,而不是在Mapper.Initialize中使用CreateMap。按照他的提示,我修改了代碼,以后再也沒有出現錯誤。
=============該總結了================
現在再次回頭看看這個問題,完全是了然於胸的感覺。因為我在AutoMapperWebconfig靜態類的靜態方法中已經進行了Mapper.Initialize(),這是AutoMapper的初始化,而在每個實體類對應的Profile類中又使用了一次。嘗試着去想一想,第一次將所有的文配置類都初始化到Mapper(暫且先將它理解成一個容器)中,第二次調用Mapper.Initialize()可能會把之前的內容都擦除掉,所以使用Mapper.Map的時候會報錯就可以想明白了,而使用DynamicMap,之前在哪里看到過DynamicMap就想當於先CreateMap,再Map,所以,我們之前的配置就可有可無,無關緊要了,因為DynamicMap會把之前的配置擦除掉,所以上面截圖中的映射成功了。而至於其他配置類沒有出現該錯誤,該回答者給的答案是”這可能是個意外!“。在這次坎坷曲折的解決問題的過程中,還是學到了很多東西的。在這里,我們也很顯然,可以看出博客園那位園友使用DynamicMap成功后而沒給出為什么,十有八九也是我這個問題了。
==============總結完畢================