使用Automapper從DTO數據中擴充實體通常是一個糟糕的主意。向相反的方向發展很好 - 將數據從實體傳遞給viewmodels,webapimodels或DTO。但特別是對於EntityFramework,在客戶端到域的方向使用它可能會變得混亂。
例如,你有你的實體2個屬性是不是在您的視圖模型:(?爲什麼外殼不一致BTW)id
和CreatedAt
。爲了使AutoMapper.Mapper.AssertConfigurationIsValid()
不引發異常,這意味着您需要忽略或使用您的CreateMap
調用中這兩個屬性的自定義解析器,以及Departments
屬性的忽略或自定義解析器。最終,自動映射的唯一東西是name
,這首先破壞了使用automapper的目的。
將DTO轉換爲實體的代碼實際上非常簡潔。說實話,我想改變的重點是去掉automapper--在這種情況下,它並不是必需的。
var reg = new Registration { name = dto.name }; // less code than with automapper
reg.Departments = new List<int>(dto.Departments)
.ConvertAll(input => Context.Departments.Find(input));
if(reg.Departments.Contains(null)) //a department provided does not exist in the database
return Request.CreateResponse(HttpStatusCode.BadRequest, "invalid department");
你可能會去嘗試,這樣的財產以後:
Mapper.CreateMap<RegistrationDTO, Registration>()
.ForMember(d => d.id, o => o.Ignore())
.ForMember(d => d.CreatedAt, o => o.UseValue(DateTime.Now))
.ForMember(d => d.Departments, o => o.MapFrom(s =>
{
var dbContext = new MyDbContext();
var departments = new List<int>(s.Departments)
.ConvertAll(input => dbContext.Departments.Find(input));
return departments;
}))
;
這不會起作用,因爲在委託塊DbContext
是不一樣的DbContext
您將使用到Registration
實體添加到(dbContext.Registrations.Add(reg)
)並調用SaveChanges
。當您將實體連接到不同的上下文時,最終會在數據庫中出現重複的Department
實體(或者由於重複的主鍵可能導致SQL異常)。
更新
我去AutoMapper,因爲我的兩個實體和DTO有超過15場,是數據庫具體的東西 我的實體擁有,喜歡的ID兩者之間 唯一的區別,建立日期,最後修改日期等。 考慮到我的實體比我在此處發佈的簡化 大很多,您是否會保持您在此情況下不使用AutoMapper的建議 ?
這取決於。對於你的15+其他屬性,它們都是標量嗎?他們中的任何一個是外鍵屬性(暴露於管理非集合導航屬性)?有多少人會要求自定義解析器?
我絕對不會使用automapper去DTO集合導航屬性(public virtual ICollection<SomeOtherEntity> OtherEntities { get; set; }
)。我也不會嘗試將automapper用於不公開外鍵的DTO非集合導航屬性(public virtual SomeOtherEntity OtherEntity { get; set; }
)。
這裏的代碼味道是,對於每個DTO實體CreateMap
調用,您至少會有幾個Ignore
(忽略創建日期,最後修改日期等)。此外,如果您的非集合導航屬性確實公開外鍵屬性,則可以自動映射fk屬性並且它將起作用,但最終會對實際(virtual
)導航屬性產生另一個忽略。
此外,當涉及到域代碼時,這是您的記錄系統,它有助於在閱讀時將所有內容全部公開,而不是在AutoMapper後面隱藏一些細節。考慮以下 - 這是更明確的,雖然它是有點冗長,我不認爲這不一定是壞事,因爲它顯示了一個源文件所有域名轉移代碼:
var reg = new Registration
{
name = dto.name,
prop1 = dto.prop1,
prop2 = dto.prop2,
...
propN = dto.propN
};
比較一下你在這裏需要多少額外的行和所有額外的行(忽略,自定義解析器等),你需要在引導程序中使用CreateMap
。最後這是你的電話,希望這有助於。
感謝您的幫助!我去了AutoMapper,因爲我的實體和DTO都有15個字段,兩者之間的唯一區別就是我的實體具有的數據庫特定的東西,比如id,創建日期,最後修改日期等。您是否保留不使用在這種情況下,AutoMapper考慮到我的實體比我在這裏發佈的簡化大得多? PS。不一致的外殼是一個錯字:P – Adabada 2013-03-24 13:54:17
我在回答中回覆了你的評論。 – danludwig 2013-03-24 14:15:11
感謝您的更新夥計,我明白了你的觀點,這很有道理。所有的屬性都是標量的,是的,所有的屬性映射到實體模型1:1,不需要自定義的解析器或任何東西。我以前爲我的模型實體設置了接受DTO的構造函數,類似於您的建議,但是用於AutoMapper,因爲這是一個我正在使用的遺留系統,並且有幾百個實體需要處理。 – Adabada 2013-03-24 15:08:27