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

如何通过特性自动注册.NET7 WebAPI中Dapper的实体映射?

自动注册Dapper Column特性映射的解决方案

问题背景

在.NET 7 WebAPI中使用Dapper时,通过自定义Column特性实现数据库列与实体类属性的映射,但目前需在Program.cs中手动为每个实体调用SqlMapper.SetTypeMap,频繁修改易引发版本控制合并冲突,需要自动化的映射注册方案。


方案1:自定义标记特性+程序集扫描

通过自定义特性标记需要注册映射的实体,再扫描程序集自动完成注册:

  1. 创建标记特性
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class DapperMappedAttribute : Attribute
{
}
  1. 为实体类添加标记
[DapperMapped]
public class Customer
{
    public int CustomerID { get; set; }

    [Column(Name = "Customer_Name")]
    public string Name { get; set; }
}
  1. 在Program.cs中添加自动注册逻辑
// 扫描当前程序集内所有标记了DapperMappedAttribute的类型
var mappedTypes = Assembly.GetExecutingAssembly()
    .GetTypes()
    .Where(t => t.GetCustomAttributes(typeof(DapperMappedAttribute), inherit: false).Any());

foreach (var type in mappedTypes)
{
    // 动态创建对应类型的ColumnAttributeTypeMapper实例
    var mapperGenericType = typeof(ColumnAttributeTypeMapper<>).MakeGenericType(type);
    var mapperInstance = Activator.CreateInstance(mapperGenericType);

    // 调用Dapper的SetTypeMap完成注册
    typeof(SqlMapper)
        .GetMethod("SetTypeMap", new[] { typeof(Type), typeof(SqlMapper.ITypeMap) })
        .Invoke(null, new object[] { type, mapperInstance });
}

方案2:自动扫描含Column特性的实体

若不想额外添加标记特性,可直接扫描所有包含Column特性属性的实体类:

var targetAssembly = Assembly.GetExecutingAssembly();
// 筛选所有包含Column特性属性的非抽象类
var entityTypes = targetAssembly.GetTypes()
    .Where(t => t.IsClass && !t.IsAbstract 
                && t.GetProperties().Any(p => p.GetCustomAttributes(typeof(ColumnAttribute), inherit: false).Any()));

foreach (var type in entityTypes)
{
    var mapperGenericType = typeof(ColumnAttributeTypeMapper<>).MakeGenericType(type);
    var mapperInstance = Activator.CreateInstance(mapperGenericType);

    typeof(SqlMapper)
        .GetMethod("SetTypeMap", new[] { typeof(Type), typeof(SqlMapper.ITypeMap) })
        .Invoke(null, new object[] { type, mapperInstance });
}

可选优化:缓存映射逻辑提升性能

原ColumnAttributeTypeMapper可添加静态缓存,避免每次反射查询属性:

public class ColumnAttributeTypeMapper<T> : FallbackTypeMapper
{
    private static readonly Dictionary<string, PropertyInfo> _columnToPropertyMap;

    static ColumnAttributeTypeMapper()
    {
        // 预加载并缓存列名与属性的映射关系
        _columnToPropertyMap = typeof(T).GetProperties()
            .SelectMany(prop => prop.GetCustomAttributes<ColumnAttribute>(false)
                .Select(attr => new { ColumnName = attr.Name, Property = prop }))
            .ToDictionary(kvp => kvp.ColumnName, kvp => kvp.Property, StringComparer.OrdinalIgnoreCase);
    }

    public ColumnAttributeTypeMapper()
        : base(new SqlMapper.ITypeMap[]
            {
                new CustomPropertyTypeMap(
                   typeof(T),
                   (type, columnName) =>
                       _columnToPropertyMap.TryGetValue(columnName, out var prop) 
                           ? prop 
                           : type.GetProperties().FirstOrDefault(p => p.Name.Equals(columnName, StringComparison.OrdinalIgnoreCase))
                   ),
                new DefaultTypeMap(typeof(T))
            })
    {
    }
}

注意事项

  • 若实体类分布在多个程序集,可通过AppDomain.CurrentDomain.GetAssemblies()遍历所有加载的程序集,注意过滤系统程序集避免无效扫描。
  • 注册逻辑需放在Program.cs中应用启动前执行,确保Dapper执行数据库操作前已完成映射配置。

内容的提问来源于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 04:34:54