使用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