AutoMapper中的Map和DynamicMap——高手注重細節,思考和總結


近日在做項目的時候,遇到了個怪問題,關於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類時,報錯如下:

E{A2JHI%`4A68KE]KR6I_}3

很明顯這是AutoMapper映射錯誤。

接下來就各種搜索錯誤,找到了下面一篇博客,原文

ta的解決方案是,如圖

image

看到這里,我很高興,趕緊改了一下自己的代碼,發現果然成功了!但是該博主並沒有給出個所以然來。

L]%SFP7IHKNLMU9V(_K}}{S

但是,我不服氣,我之前已經創建了兩個類之間的映射啊,為啥Mapper.Map()方法不行,我就納悶了,我非得搞清楚這兩者之間的關系不可。

我尋思着,就字面意思來看,一個是“映射”,一個是“動態映射”,會有啥區別呢?

於是各種搜兩者之間的區別,去StackOverflow上找到了下面的答案:原鏈接

image

這里說,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,在這里,我得到了我想要的答案。

image

該回答者給我的答案如上,他猜想我在每個實體類對應的Profile文件中,應該直接使用CreateMap,而不是在Mapper.Initialize中使用CreateMap。按照他的提示,我修改了代碼,以后再也沒有出現錯誤。

=============該總結了================

現在再次回頭看看這個問題,完全是了然於胸的感覺。因為我在AutoMapperWebconfig靜態類的靜態方法中已經進行了Mapper.Initialize(),這是AutoMapper的初始化,而在每個實體類對應的Profile類中又使用了一次。嘗試着去想一想,第一次將所有的文配置類都初始化到Mapper(暫且先將它理解成一個容器)中,第二次調用Mapper.Initialize()可能會把之前的內容都擦除掉,所以使用Mapper.Map的時候會報錯就可以想明白了,而使用DynamicMap,之前在哪里看到過DynamicMap就想當於先CreateMap,再Map,所以,我們之前的配置就可有可無,無關緊要了,因為DynamicMap會把之前的配置擦除掉,所以上面截圖中的映射成功了。而至於其他配置類沒有出現該錯誤,該回答者給的答案是”這可能是個意外!“。在這次坎坷曲折的解決問題的過程中,還是學到了很多東西的。在這里,我們也很顯然,可以看出博客園那位園友使用DynamicMap成功后而沒給出為什么,十有八九也是我這個問題了。

==============總結完畢================


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM