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

如何自动注册实现IModel接口的Dapper模型类?

Dapper模型自动注册解决方案

问题背景

我使用ColumnAttributeTypeMapper实现Dapper模型与SQL列名的映射,目前需要为每个模型手动执行以下注册代码:

Dapper.SqlMapper.SetTypeMap(typeof(FooModel), new ColumnAttributeTypeMapper<FooModel>());
// 其他模型同理

为了实现自动化注册,我定义了IModel接口:

public interface IModel {}

并编写了扩展方法扫描所有实现该接口的类,尝试批量注册:

public static class WebApplicationExtensions
{
    public static void MapModels(this WebApplication app)
    {
        var assemblies = AppDomain.CurrentDomain.GetAssemblies();
            
        var classes = assemblies.Distinct().SelectMany(x => x.GetTypes())
            .Where(x => typeof(IModel).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract);

        foreach (var classe in classes)
        {
            Dapper.SqlMapper.SetTypeMap(classe, new ColumnAttributeTypeMapper<classe>());
        }
    }
}

// 调用代码
app.MapModels();

但编译报错:'classe' is a variable but is used like a type,尝试其他写法也无效,请问如何在.NET中实现这些Dapper模型的自动注册?

解决方案

编译报错的核心原因是:泛型类型参数必须在编译时确定,而classe是运行时动态获取的Type变量,无法直接作为泛型参数使用。需要通过反射创建泛型实例来解决这个问题。

修正后的自动注册代码

public static class WebApplicationExtensions
{
    public static void MapModels(this WebApplication app)
    {
        // 扫描所有包含IModel实现的程序集
        var modelTypes = AppDomain.CurrentDomain.GetAssemblies()
            .Distinct()
            .SelectMany(assembly => assembly.GetTypes())
            .Where(type => typeof(IModel).IsAssignableFrom(type) 
                           && !type.IsInterface 
                           && !type.IsAbstract);

        // 获取ColumnAttributeTypeMapper的泛型定义(未绑定类型参数)
        var mapperGenericDefinition = typeof(ColumnAttributeTypeMapper<>);
        
        foreach (var modelType in modelTypes)
        {
            // 生成绑定当前模型类型的具体泛型类型
            var mapperConcreteType = mapperGenericDefinition.MakeGenericType(modelType);
            // 创建泛型类型实例
            var mapperInstance = Activator.CreateInstance(mapperConcreteType);
            
            // 注册Dapper类型映射
            Dapper.SqlMapper.SetTypeMap(modelType, mapperInstance);
        }
    }
}

关键逻辑说明

  1. 获取泛型定义:通过typeof(ColumnAttributeTypeMapper<>)获取未绑定类型参数的泛型类型模板。
  2. 生成具体泛型类型:使用MakeGenericType(modelType)将动态获取的模型类型绑定到泛型模板上,得到可实例化的具体类型。
  3. 创建实例并注册:通过Activator.CreateInstance创建泛型实例,再传递给SqlMapper.SetTypeMap完成自动注册。

可选优化:缩小程序集扫描范围

如果项目程序集较多,可以只扫描包含IModel的程序集及其引用程序集,提升扫描效率:

public static void MapModels(this WebApplication app)
{
    // 获取IModel所在的程序集
    var baseAssembly = typeof(IModel).Assembly;
    // 扫描所有引用该程序集的程序集,加上基础程序集本身
    var targetAssemblies = AppDomain.CurrentDomain.GetAssemblies()
        .Where(assembly => assembly.GetReferencedAssemblies()
            .Any(asm => asm.FullName == baseAssembly.FullName))
        .Append(baseAssembly)
        .Distinct();

    var modelTypes = targetAssemblies
        .SelectMany(assembly => assembly.GetTypes())
        .Where(type => typeof(IModel).IsAssignableFrom(type) 
                       && !type.IsInterface 
                       && !type.IsAbstract);

    var mapperGenericDefinition = typeof(ColumnAttributeTypeMapper<>);
    foreach (var modelType in modelTypes)
    {
        var mapperConcreteType = mapperGenericDefinition.MakeGenericType(modelType);
        var mapperInstance = Activator.CreateInstance(mapperConcreteType);
        Dapper.SqlMapper.SetTypeMap(modelType, mapperInstance);
    }
}

内容的提问来源于stack exchange,提问作者Jon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 01:52:41