Automapper 12.x依赖注入实现ConstructUsing绑定NHibernate会话实体的问题
解决方案:Automapper 12.x 结合 NHibernate 会话实现 DTO 到绑定实体的映射
核心思路是利用 Automapper 12.x 提供的 ResolutionContext.Services(替代原 ServiceCtor)获取 NHibernate 会话,通过统一配置 ConstructUsing 完成实体的加载/创建,让 Automapper 自动处理属性映射,避免无限循环和手动映射的冗余操作。
1. 调整 Automapper 核心配置
直接在全局映射配置中处理实体的加载逻辑,无需单独编写 TypeConverter:
var mapperConfig = new MapperConfiguration(cfg => { // 注册你的映射 Profile 或其他基础配置 cfg.AddProfile<YourBusinessMappingProfile>(); // 全局处理 IHasId DTO 到 IEntity 实体的映射 cfg.Internal().ForAllMaps((typeMap, mappingExpr) => { if (typeof(IEntity).IsAssignableFrom(typeMap.DestinationType) && typeof(IHasId).IsAssignableFrom(typeMap.SourceType)) { mappingExpr.ConstructUsing((source, context) => { // 从当前服务上下文获取 NHibernate 会话 var session = context.Services.GetRequiredService<ISession>(); var sourceWithId = source as IHasId; // 处理新建实体场景(DTO 的 Id 为默认值) if (sourceWithId?.Id == default) { return Activator.CreateInstance(typeMap.DestinationType); } // 优先从会话加载实体,不存在则新建 var entity = session.Get(typeMap.DestinationType, sourceWithId.Id); return entity ?? Activator.CreateInstance(typeMap.DestinationType); }); } }); cfg.AllowNullDestinationValues = true; });
2. 正确注册 IMapper 到依赖注入容器
确保 IMapper 能获取到当前作用域的 NHibernate 会话,将其注册为 Scoped 服务:
services.AddScoped<IMapper>(sp => { var config = new MapperConfiguration(cfg => { // 复用上面的配置代码 cfg.AddProfile<YourBusinessMappingProfile>(); cfg.Internal().ForAllMaps(...); cfg.AllowNullDestinationValues = true; }); config.AssertConfigurationIsValid(); // 验证映射配置合法性 return config.CreateMapper(sp); });
3. 方案优势说明
- 避免无限循环:
ConstructUsing仅负责实体的加载/创建,属性映射由 Automapper 自动完成,无需手动调用context.Mapper.Map,彻底杜绝递归触发问题。 - 实体自动绑定会话:通过
session.Get加载的实体直接绑定到当前 NHibernate 会话,新建实体后续保存时也会被会话自动追踪。 - 无侵入式改造:全局配置统一处理所有实体映射逻辑,业务层只需正常调用
mapper.Map<TEntity>(dto),无需修改现有业务代码。
针对参数化构造函数实体的补充
若你的实体使用参数化构造函数(而非无参构造),可修改实体创建逻辑,通过 DI 容器实例化:
// 替换原 Activator.CreateInstance 代码 var entity = context.Services.GetService(typeMap.DestinationType) ?? Activator.CreateInstance(typeMap.DestinationType);
这样可确保实体构造函数的依赖项被正确注入。
内容的提问来源于stack exchange,提问作者Freak78
相关产品推荐
相关产品推荐

