Dapper and Enums as Strings
Thanks to Marc Gravell reply:
The only way is to do the inserts manually.
Also using the following post: How do I perform an insert and return inserted identity with Dapper?
Below my solution.
Note that selects work automatically: you can use Dapper (Extensions) directly GetList<T>
, there is no mapping to the enum back required.
public enum ComponentType
{
First,
Second,
Third
}
public class Info
{
public int Id { get; set; }
public ComponentType InfoComponentType { get; set; }
public static void SaveList(List<Info> infoList)
{
string ConnectionString = GetConnectionString();
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
conn.Open();
foreach (Info info in infoList)
{
string sql = @"INSERT INTO [Info] ([InfoComponentType])
VALUES (@InfoComponentType);
SELECT CAST(SCOPE_IDENTITY() AS INT)";
int id = conn.Query<int>(sql, new
{
InfoComponentType = info.InfoComponentType.ToString()
}).Single();
info.Id = id;
}
conn.Close();
}
}
}
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.