[英]AutoMapper How To Map Object A To Object B Differently Depending On Context
調用所有AutoMapper大師!
我希望能夠根據運行時的上下文以不同方式將對象A映射到對象B. 特別是,我想在一個映射的情況下忽略某些屬性,並在另一個案例中映射所有屬性。
我所經歷的是Mapper.CreateMap可以在不同的映射情況下成功調用,但是,一旦調用了CreateMap,就會設置特定的一對類型的映射,並且隨后的CreateMap調用不會改變它,這可能會描述映射不同。
我找到了一篇博客文章,主張Mapper.Reset()來解決這個問題,然而,Mapper類的靜態特性意味着碰撞和崩潰發生只是時間問題。
有沒有辦法做到這一點?
我認為我需要的是每個appdomain調用Mapper.CreateMap一次,然后,能夠調用Mapper.Map,提示應該包含/排除哪些屬性。
現在,我正在考慮通過編寫一個包含映射配置實例的非靜態映射類來更改源代碼。 性能不佳,但線程安全。
我有什么選擇。 可以做些什么? Automapper似乎很有前途。
只是為了補充Jimmy的答案,這里是在沒有靜態Mapper的情況下使用AutoMapper所需的代碼
從版本4.2.1開始, Automapper有一個受制裁的非靜態映射器和配置(感謝Jimmy!)。
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<ClassA, ClassB>();
});
var mapper = config.CreateMapper();
新版本中還有許多其他有用的選項(如配置文件),用於創建不同的映射器實例。 您可以在官方文檔中獲取所有詳細信息
(對於4.1.1版本更正)
// Configuration
AutoMapper.Mappers.MapperRegistry.Reset();
var autoMapperCfg = new AutoMapper.ConfigurationStore(new TypeMapFactory(), AutoMapper.Mappers.MapperRegistry.Mappers);
var mappingEngine = new AutoMapper.MappingEngine(autoMapperCfg);
autoMapperCfg.Seal();
//Usage example
autoMapperCfg.CreateMap<ClassA, ClassB>();
var b = mappingEngine.Map<ClassB>(a);
(對於版本3.2.1更正)
// Configuration
var platformSpecificRegistry = AutoMapper.Internal.PlatformAdapter.Resolve<IPlatformSpecificMapperRegistry>();
platformSpecificRegistry.Initialize();
var autoMapperCfg = new AutoMapper.ConfigurationStore(new TypeMapFactory(), AutoMapper.Mappers.MapperRegistry.Mappers);
var mappingEngine = new AutoMapper.MappingEngine(autoMapperCfg);
//Usage example
autoMapperCfg.CreateMap<ClassA, ClassB>();
var b = mappingEngine.Map<ClassB>(a);
(對於2.2.1版本更正)
// Configuration
var autoMapperCfg = new AutoMapper.ConfigurationStore(new AutoMapper.TypeMapFactory(), AutoMapper.Mappers.MapperRegistry.AllMappers());
var mappingEngine = new AutoMapper.MappingEngine(autoMapperCfg);
//Usage example
autoMapperCfg.CreateMap<ClassA, ClassB>();
var b = mappingEngine.Map<ClassB>(a);
Mapper類只是Configuration和MappingEngine對象之上的一個瘦包裝器。 您可以創建Configuration / MappingEngine對象的單獨實例(仍使用單例),並根據需要使用您選擇的IoC容器加載正確的容器。
最好的選擇仍然是使用不同的目標類型。 關於真正支持此功能的真正困難的部分是類型映射的固有層次性。 頂級對象可能具有映射配置文件,而較低級別的對象可能沒有。 介於兩者之間可能有或沒有等等。
對我來說,聽起來更好的設計可能是擁有多個目標類(可能繼承自公共基礎或實現通用接口)
如果未在其中一個變體中使用未映射的屬性,則可以將它們完全保留(使編譯時保證不會錯誤地使用它們),在訪問它們時拋出異常(不如編譯時間那么好)保證,但有時您需要實現完整的接口)或甚至使用替代值。
例如:
public class Source
{
public string Name {get;set;}
public BigEntity {get;set;}
/* other members */
}
public class SourceDTO
{
public string Name {get;set;}
public BigEntity {get;set;}
}
public class SourceSummaryDTO
{
public string Name {get;set;}
}
或者,你可以這樣做:
public class SourceSummaryDTO : SourceDTO
{
public string Name {get;set;}
public BigEntity
{
get{throw new NotSupportedException();}
set{throw new NotSupportedException();}
}
}
這樣,您可以傳遞SourceSummaryDTO,就像它是SourceDTO一樣。
擁有有條件填充的屬性聽起來像是給我帶來麻煩的一個秘訣 - 我寧願讓類明確知道它們包含什么,尤其是數據傳輸對象。
對我來說,Automapper的最大優點是能夠驗證映射,然后知道目標類的每個屬性都將被填充。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.