Skip to content

Instantly share code, notes, and snippets.

@pedroinfo
Last active March 23, 2026 19:46
Show Gist options
  • Select an option

  • Save pedroinfo/456029bbe86ecb0d53a089a5bbe9e62b to your computer and use it in GitHub Desktop.

Select an option

Save pedroinfo/456029bbe86ecb0d53a089a5bbe9e62b to your computer and use it in GitHub Desktop.
Dapper Mapping Columns
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Reflection;
using Dapper;
namespace YourProject.Infrastructure.Dapper
{
/// <summary>
/// Mapeador robusto para Dapper que suporta [Column("nome")].
/// Resolve o erro de proteção de nível de acesso do SimpleMemberMap.
/// </summary>
public class ColumnAttributeTypeMapper<T> : SqlMapper.ITypeMap
{
private readonly SqlMapper.ITypeMap _defaultMap;
// Cache estático para mapear NomeDaColuna -> NomeDaPropriedade no C#
private static readonly ConcurrentDictionary<string, string> _columnToPropNameCache = new(StringComparer.OrdinalIgnoreCase);
public ColumnAttributeTypeMapper()
{
_defaultMap = new DefaultTypeMap(typeof(T));
lock (_columnToPropNameCache)
{
if (_columnToPropNameCache.IsEmpty)
{
var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var prop in properties)
{
var columnAttr = prop.GetCustomAttribute<ColumnAttribute>();
if (columnAttr != null && !string.IsNullOrWhiteSpace(columnAttr.Name))
{
_columnToPropNameCache.TryAdd(columnAttr.Name, prop.Name);
}
}
}
}
}
public SqlMapper.IMemberMap GetMember(string columnName)
{
// 1. Se a coluna está no nosso cache de atributos,
// pedimos ao DefaultTypeMap para encontrar a propriedade pelo nome real dela no C#
if (_columnToPropNameCache.TryGetValue(columnName, out var propertyName))
{
return _defaultMap.GetMember(propertyName);
}
// 2. Fallback: tenta o mapeamento padrão (caso o nome da coluna no SQL seja igual ao da prop)
return _defaultMap.GetMember(columnName);
}
// Métodos obrigatórios (Repasse)
public ConstructorInfo FindConstructor(string[] names, Type[] types) => _defaultMap.FindConstructor(names, types);
public ConstructorInfo FindExplicitConstructor() => _defaultMap.FindExplicitConstructor();
public SqlMapper.IMemberMap GetConstructorParameter(ConstructorInfo constructor, string columnName) => _defaultMap.GetConstructorParameter(constructor, columnName);
}
public static class DapperMapperConfig
{
public static void RegisterColumnMappings(params Assembly[] assemblies)
{
var types = assemblies.SelectMany(a => a.GetTypes())
.Where(t => t.IsClass && !t.IsAbstract);
foreach (var type in types)
{
var hasColumnAttr = type.GetProperties()
.Any(p => Attribute.IsDefined(p, typeof(ColumnAttribute)));
if (hasColumnAttr)
{
var mapperType = typeof(ColumnAttributeTypeMapper<>).MakeGenericType(type);
var mapperInstance = (SqlMapper.ITypeMap)Activator.CreateInstance(mapperType);
SqlMapper.SetTypeMap(type, mapperInstance);
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment