Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mapping Enum to string column with custom SqlMapper.ITypeHandler - Dapper

Tags:

c#

enums

orm

dapper

I have a large number of PL/SQL stored procs that return columns with single character strings representing some kind of status value from a fixed range. In the project I'm working on, these columns have been mapped by Dapper to string properties on the domain objects, which are awkward and unreliable to manage, so I'd like to switch to enums.

If I used enums with single character names like enum Foo {A, P} I'm pretty sure Dapper would map them correctly but I don't want that, I want enums with descriptive labels like so:

enum Foo {
    [StringValue("A")]
    Active,
    [StringValue("P")]
    Proposed
}

In the above example, StringValueAttribute is a custom attribute and I can use reflection to convert the "A" to Foo.Active, which works fine - except I need Dapper to perform that conversion logic for me. I wrote a custom type handler to do this:

public class EnumTypeHandler<T> : SqlMapper.TypeHandler<T>
{
    public override T Parse(object value)
    {
        if (value == null || value is DBNull) { return default(T); }
        return EnumHelper.FromStringValue<T>(value.ToString());
    }

    public override void SetValue(IDbDataParameter parameter, T value)
    {
        parameter.DbType = DbType.String;
        parameter.Value = EnumHelper.GetStringValue(value as Enum);
    }
}

//Usage:
SqlMapper.AddTypeHandler(typeof(Foo),
    (SqlMapper.ITypeHandler)Activator.CreateInstance(typeof(EnumTypeHandler<>).MakeGenericType(typeof(Foo)));

The registration with SqlMapper.AddTypeHandler() seems to work fine, but when my DbConnection.Query() code runs, I get an error saying that the value 'A' could not be converted - the error is thrown from Enum.Parse, suggesting that Dapper isn't actually calling my type handler at all despite it being registered. Does anyone know a way around this?

like image 829
wwarby Avatar asked Apr 02 '15 12:04

wwarby


1 Answers

Another user has reported this as an issue on Dapper's github site. Seems like it's a deliberate optimisation specifically around enums in Dapper, so I've changed my database model rather than trying to change the mapping code. I looked at trying to modify Dapper itself, but the source code of Dapper is optimised like nothing I've ever seen, emitting opcodes to perform conversions in the most performant way possible - no way I want to start trying to work out how to make changes there.

like image 119
wwarby Avatar answered Sep 16 '22 13:09

wwarby