前幾天發現 AutoMapper 3.3 的一個性能問題(詳見:遭遇AutoMapper性能問題:映射200條數據比100條慢了近千倍),於是將 AutoMapper 升級至最新的 5.1.1 看是否也存在這個性能問題。
升級中想當然地將之前的map配置代碼:
Mapper.CreateMap<AEntity, ADto>(); Mapper.CreateMap<BEntity, BDto>();
改為:
Mapper.Initialize(cfg => cfg.CreateMap<AEntity, ADto>()); Mapper.Initialize(cfg => cfg.CreateMap<BEntity, BDto>());
但是代碼運行時在執行 Mapper.Map() 時出現下面的錯誤:
Missing type map configuration or unsupported mapping
在執行 ProjectTo() 時出現下面的錯誤:
System.InvalidOperationException: Missing map from AEntity to ADto. Create using Mapper.CreateMap<AEntity, ADto>. 在 AutoMapper.QueryableExtensions.ExpressionBuilder.CreateMapExpression...
當時百思不得其解,折騰了一段時間無果,就暫時放在一邊。
今天在博問上發現有人遇到了同樣的問題——求解AutoMapper映射類發生錯誤求解,於是解決這個問題的興趣被激發,又開始折騰。
在折騰的過程中發現,如果不用 Mapper.Initialize() 這種靜態的配置方式,改用下面的實例配置方式,就不會出現這個問題。
var config = new MapperConfiguration(cfg => cfg.CreateMap<A, B>()); var mapper = config.CreateMapper(); mapper.Map<List<B>>(list);
Mapper.Initialize() 理所當然地成了最大的嫌疑對象,於是從 GitHub 上簽出 AutoMapper 的源代碼一看 Mapper.Initialize() 的實現,恍然大悟。
public static void Initialize(Action<IMapperConfigurationExpression> config) { Configuration = new MapperConfiguration(config); Instance = new Mapper(Configuration); }
原來每次調用 Mapper.Initialize() 都會創建新的 Mapper 實例,也就是多次調用 Mapper.Initialize() 只有最后一次生效。
下面的配置代碼中生效的只是第2行(BEntity到BDto的map),第1行(AEntity到ADto的map)沒生效,從而出現前面所說的錯誤。
Mapper.Initialize(cfg => cfg.CreateMap<AEntity, ADto>()); Mapper.Initialize(cfg => cfg.CreateMap<BEntity, BDto>());
知道了原因,解決起來就手到擒來,改為下面的代碼即可。
var cfg = new MapperConfigurationExpression(); cfg.CreateMap<AEntity, ADto>(); cfg.CreateMap<BEntity, BDto>(); Mapper.Initialize(cfg);
解決這個問題后,成功完成了 AutoMapper 的升級,然后驗證了 AutoMapper 3.3 的性能問題在 AutoMapper 5.1.1 中不存在。