我们正在使用 Automapper 将 DTO 映射到实体。
为了确保创建的实体始终绑定到会话(我们使用 NHibernate),我们在 Automapper 配置中有以下内容:
var mapperConfig = new MapperConfiguration(cfg =>
{
// Do other stuff
cfg.Internal().ForAllMaps((tm, me) =>
{
if (typeof(IEntity).IsAssignableFrom(tm.DestinationType) &&
typeof(IHasId).IsAssignableFrom(tm.SourceType))
{
var entityResolverType = typeof(EntityResolver<,>).MakeGenericType(tm.SourceType, tm.DestinationType);
me.ConstructUsing((source, context) =>
{
var resolver = context.Options.ServiceCtor.Invoke(entityResolverType) as IEntityResolver;
return resolver.Resolve(source);
});
}
});
cfg.AllowNullDestinationValues = true;
});
现在在 Automapper 12.x 中,无法再访问
ServiceCtor
中的 ResolutionContext
,我们必须考虑另一个解决方案。
我写了一个
ITypeConverter
。但这里的问题是,创建实体后,属性没有映射。
如果我使用
public class EntityTypeConverter<TModel, TEntity> : ITypeConverter<TModel, TEntity>
where TModel : IHasId
where TEntity : IEntity
{
private readonly ISession session;
public EntityTypeConverter(ISession session) { this.session = session; }
public TEntity Convert(TModel source, TEntity destination, ResolutionContext context)
{
if (destination is null)
{
destination = session.Get<TEntity>(source.Id);
destination ??= Activator.CreateInstance<TEntity>();
}
context.Mapper.Map(source, destination);
return destination;
}
}
我陷入了无限循环。
我也不能使用
AfterMap
,因为它是一个void方法,并且实体不是通过ref传递的。因此,我可以加载实体,但 Automapper 仍会返回未绑定的实例。
第三种解决方案是将会话传递给选项中的
Mapper.Map
,然后通过Mapper.Items
访问它。但为此我必须修改很多代码行,而且也不能保证将来每个程序员都会记得这样做。
我不明白为什么这么复杂。这是一种不寻常的方法来编写一个通用类,为每个 DTO 从 session/dbContext 加载适当的实体,然后才将 DTO 中的新值映射到实体中?
有谁知道如何使用 DTO、构造函数、作用域和绑定实体来实现它?
感谢您的帮助。
确保您的 DTO 属性是公共的,并且具有 public get set 修饰符。