Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dapper and Enums as Strings

Tags:

c#

.net

dapper

I am trying to use Dapper and Dapper-Extensions and to serialize my enums on the database as string.

Right now they are serialized as integers (inside a VARCHAR field) instead.

Is there any way to do this? Any custom type mapping that I can add?

I might need to move back to EF if i can't pull this through..

like image 340
MaurGi Avatar asked May 16 '16 23:05

MaurGi


People also ask

Can enums be strings?

No they cannot. They are limited to numeric values of the underlying enum type.

Can C# enums be strings?

Since C# doesn't support enum with string value, in this blog post, we'll look at alternatives and examples that you can use in code to make your life easier. The most popular string enum alternatives are: Use a public static readonly string. Custom Enumeration Class.

What happens if you ToString an enum?

ToString(String)Converts the value of this instance to its equivalent string representation using the specified format.

What is enum parse in C#?

The Parse method in Enum converts the string representation of the name or numeric value of enum constants to an equivalent enumerated object.

How do I read enum values in Dapper?

By default Dapper will store an enum in the database as an integer. The simplest way around this is to just call ToString () whenever saving to the database. Reading from the database is much less of an issue as Dapper can parse either an integer or string to the correct enum value.

How can I read enum values from the database?

The simplest way around this is to just call ToString () whenever saving to the database. Reading from the database is much less of an issue as Dapper can parse either an integer or string to the correct enum value.

Is it possible to use string-based enums in C #?

Using string-based enums in C# is not supported and throws a compiler error. Since C# doesn't support enum with string value, in this blog post, we'll look at alternatives and examples that you can use in code to make your life easier.

Why do we use enums in our persistence layer?

Our persistence layer uses Dapper and like most other ORMs it persists Enums using the backing integer value. Same goes for JSON serialization. So while an enum does provide us a convenient mechanism for constraining our type’s values, it leaves us constantly having to convert (and validate) to and from the string representation.


1 Answers

There's a way, which I think is more robust and clean.

The solution I provide will work for any enumeration, but it involves some extra coding. It also involves adding a custom type handler in Dapper. However, if this answer gets some votes, I will change the Dapper source code to include this solution automatically in the type handling and ask for a pull request.

I actually implemented this solution and use it in production.

Here goes.

First the struct (not a class, because the struct simply holds a string reference) that will be used as enumeration:

public struct Country
{
    string value;

    public static Country BE => "BE";
    public static Country NL => "NL";
    public static Country DE => "DE";
    public static Country GB => "GB";

    private Country(string value)
    {
        this.value = value;
    }

    public static implicit operator Country(string value)
    {
        return new Country(value);
    }

    public static implicit operator string(Country country)
    {
        return country.value;
    }
}

Now we need a type handler for this struct

public class CountryHandler : SqlMapper.ITypeHandler
{
    public object Parse(Type destinationType, object value)
    {
        if (destinationType == typeof(Country))
            return (Country)((string)value);
        else return null;
    }

    public void SetValue(IDbDataParameter parameter, object value)
    {
        parameter.DbType = DbType.String;
        parameter.Value = (string)((dynamic)value);
    }
}

Somewhere in the startup of the application we have to register the type handler with Dapper

Dapper.SqlMapper.AddTypeHandler(typeof(Country), new CountryHandler());

Now you can simply use Country as an "enum". For instance:

public class Address
{
     public string Street { get; set; }
     public Country Country { get; set; }
}

var addr = new Address { Street = "Sesamestreet", Country = Country.GB };

The downside of course is that the enumeration is not backed in memory by an integer but by a string.

like image 118
neeohw Avatar answered Sep 18 '22 08:09

neeohw