我的技术与 neeohw 的相似,但我可以使用真正的枚举。而且它是通用的,所以我不必写很多次。
有一个包装枚举值的不可变结构。它有一个单一的属性和隐式转换,以及一个通用的自定义类型处理程序。
public readonly struct DapperableEnum<TEnum> where TEnum : Enum
{
[JsonConverter(typeof(StringEnumConverter))]
public TEnum Value { get; }
static DapperableEnum()
{
Dapper.SqlMapper.AddTypeHandler(typeof(DapperableEnum<TEnum>), new DapperableEnumHandler<TEnum>());
}
public DapperableEnum(TEnum value)
{
Value = value;
}
public DapperableEnum(string description)
{
Value = EnumExtensions.GetValueByDescription<TEnum>(description);
}
public static implicit operator DapperableEnum<TEnum>(TEnum v) => new DapperableEnum<TEnum>(v);
public static implicit operator TEnum(DapperableEnum<TEnum> v) => v.Value;
public static implicit operator DapperableEnum<TEnum>(string s) => new DapperableEnum<TEnum>(s);
}
public class DapperableEnumHandler<TEnum> : SqlMapper.ITypeHandler
where TEnum : Enum
{
public object Parse(Type destinationType, object value)
{
if (destinationType == typeof(DapperableEnum<TEnum>))
{
return new DapperableEnum<TEnum>((string)value);
}
throw new InvalidCastException($"Can't parse string value {value} into enum type {typeof(TEnum).Name}");
}
public void SetValue(IDbDataParameter parameter, object value)
{
parameter.DbType = DbType.String;
parameter.Value =((DapperableEnum<TEnum>)value).Value.GetDescription();
}
}
我使用静态构造函数在启动时自动注册类型处理程序。
我使用 GetDescription / GetValueByDescription(与 this answer 相同的想法)来支持不是有效 C# 枚举值的字符串。如果你不需要这个功能,ToString 和 Enum.Parse 可以正常工作。
JsonConverter 属性使 Json.Net 也使用字符串值。如果你不使用 Json.Net,当然删除它
这是一个例子:
enum Holiday
{
Thanksgiving,
Christmas,
[Description("Martin Luther King, Jr.'s Birthday")]
MlkDay,
Other,
}
class HolidayScheduleItem : IStandardDaoEntity<HolidayScheduleItem>
{
public DapperableEnum<Holiday> Holiday {get; set;}
public DateTime When {get; set;}
}
并且调用代码可以使用正常的枚举值。
var item = new HolidayScheduleItem()
{
Holiday = Holiday.MlkDay,
When = new DateTime(2021, 1, 18)
};
它适用于普通的 Dapper 或 Dapper.Contrib:
await conn.ExecuteAsync("INSERT HolidayScheduleItem ([Holiday], [When])
VALUES(@Holiday, @When)", item);
await conn.InsertAsync(item);