DapperLib / Dapper

Dapper - a simple object mapper for .Net
https://www.learndapper.com/
Other
17.29k stars 3.67k forks source link

Feature Request: Type-safe Mapping #2082

Open jgador opened 2 months ago

jgador commented 2 months ago

Awareness of Existing Features: I am not aware of whether this feature already exists in newer versions of Dapper. If it does, please forgive the redundancy of this request. However, if it doesn't exist, I believe it would be a valuable addition to the library.

When using Dapper for object mapping, there isn't a built-in functionality for type-safe mapping of database columns to object properties. Columns returned from the database may not exactly match the properties of the POCO.

Example Use Case:

public class MyPocoClass
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime DateOfBirth { get; set; }
}

var personMapping = new Dictionary<string, Expression<Func<MyPocoClass, object>>>()
{
    { "Id", map => map.Id },
    { "FullName", map => map.Name },
    { "BirthDate", map => map.DateOfBirth }
};

// Custom type-safe mapping:
CustomSqlTypeMap.Map(personMapping );

In the above example, personMapping is a dictionary where the keys represent column names in the database, and the values are expressions that map those column values to corresponding properties in the MyPocoClass. This provides a clear and type-safe way to define the mapping between database columns and C# object properties.

I've created a sample utility class to address this issue:

public static class CustomSqlTypeMap
{
    /// <summary>
    /// Set custom mapping for type <typeparamref name="TEntity"/>.
    /// </summary>
    /// <typeparam name="TEntity">The CLR object to be hydrated with query results.</typeparam>
    /// <param name="memberMaps">Dictionary of mapping rules. Use the table column name as key to map with property from <typeparamref name="TEntity"/>.</param>
    public static void Map<TEntity>([NotNull] IReadOnlyDictionary<string, Expression<Func<TEntity, object>>> memberMaps)
        where TEntity : class
    {
        if (SqlMapper.GetTypeMap(typeof(TEntity)) is DefaultTypeMap)
        {
            var typeMap = new CustomPropertyTypeMap(typeof(TEntity),
                (type, columnName) => MapProperty(memberMaps).Invoke(type, columnName));

            SqlMapper.SetTypeMap(typeof(TEntity), typeMap);
        }
    }
}