You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 11:33:21