Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sebfischer83/458f2acb12da2785a2334e80a6e8d4c6 to your computer and use it in GitHub Desktop.
Save sebfischer83/458f2acb12da2785a2334e80a6e8d4c6 to your computer and use it in GitHub Desktop.
Map column names with class properties in Dapper-dot-net using ITypeMap and CustomAttributes
namespace YourNamespace
{
/// <summary>
/// Uses the Name value of the ColumnAttribute specified, otherwise maps as usual.
/// </summary>
/// <typeparam name="T">The type of the object that this mapper applies to.</typeparam>
public class ColumnAttributeTypeMapper<T> : FallbackTypeMapper
{
public static readonly string ColumnAttributeName = "ColumnAttribute";
public ColumnAttributeTypeMapper()
: base(new SqlMapper.ITypeMap[]
{
new CustomPropertyTypeMap(typeof (T), SelectProperty),
new DefaultTypeMap(typeof (T))
})
{
}
private static PropertyInfo SelectProperty(Type type, string columnName)
{
return
type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).
FirstOrDefault(
prop =>
prop.GetCustomAttributes(false)
// Search properties to find the one ColumnAttribute applied with Name property set as columnName to be Mapped
.Any(attr => attr.GetType().Name == ColumnAttributeName
&&
attr.GetType().GetProperties(BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance)
.Any(
f =>
f.Name == "Name" &&
f.GetValue(attr).ToString().ToLower() == columnName.ToLower()))
&& // Also ensure the property is not read-only
(prop.DeclaringType == type
? prop.GetSetMethod(true)
: prop.DeclaringType.GetProperty(prop.Name,
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance).GetSetMethod(true)) != null
);
}
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class ColumnAttribute : Attribute
{
public string Name { get; set; }
public ColumnAttribute() {}
public ColumnAttribute(string Name) { this.Name = Name; }
}
public class FallbackTypeMapper : SqlMapper.ITypeMap
{
private readonly IEnumerable<SqlMapper.ITypeMap> _mappers;
public FallbackTypeMapper(IEnumerable<SqlMapper.ITypeMap> mappers)
{
_mappers = mappers;
}
public ConstructorInfo FindConstructor(string[] names, Type[] types)
{
foreach (var mapper in _mappers)
{
try
{
ConstructorInfo result = mapper.FindConstructor(names, types);
if (result != null)
{
return result;
}
}
catch (NotImplementedException)
{
}
}
return null;
}
public SqlMapper.IMemberMap GetConstructorParameter(ConstructorInfo constructor, string columnName)
{
foreach (var mapper in _mappers)
{
try
{
var result = mapper.GetConstructorParameter(constructor, columnName);
if (result != null)
{
return result;
}
}
catch (NotImplementedException)
{
}
}
return null;
}
public SqlMapper.IMemberMap GetMember(string columnName)
{
foreach (var mapper in _mappers)
{
try
{
var result = mapper.GetMember(columnName);
if (result != null)
{
return result;
}
}
catch (NotImplementedException)
{
}
}
return null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment