Last active
March 23, 2026 19:46
-
-
Save pedroinfo/456029bbe86ecb0d53a089a5bbe9e62b to your computer and use it in GitHub Desktop.
Dapper Mapping Columns
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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