Как отобразить перечисление C# в перечисление PostgreSQL с помощью Dapper.FastCRUD?
У меня есть класс Sample
одним из свойств которого является перечисление, TargetType
, У меня есть соответствующая таблица samples
определенный в базе данных PostgreSQL, наряду с соответствующим типом перечисления, targettypes
,
С Dapper.FastCRUD я могу успешно извлекать записи из таблицы. Тем не менее, я получаю ошибку во время вставки:
Npgsql.PostgresException (0x80004005): 42804: column "target_type" is of type targettype but expression is of type integer
РЕДАКТИРОВАТЬ 1: MoonStorm - создатель Dapper.FastCRUD - пояснил, что преобразования типов DB-CLR обрабатываются Dapper. Итак, теперь вопрос:
Как мне сказать Dapper для сопоставления C# enum TargetType
в PostgreSQL ENUM TYPE targettype
?
Перечисление определяется как:
public enum TargetType
{
[NpgsqlTypes.PgName("Unknown")]
UNKNOWN = 0,
[NpgsqlTypes.PgName("Animal")]
ANIMAL = 1,
[NpgsqlTypes.PgName("Car")]
CAR = 2,
[NpgsqlTypes.PgName("Truck")]
TRUCK = 3
}
И класс определяется как:
[Table("samples")]
public partial class Sample
{
[Column("recording_time")]
public DateTime RecordingTime { get; set; }
[Column("x_position")]
public double X_Position { get; set; }
[Column("x_velocity")]
public double X_Velocity { get; set; }
[Column("y_position")]
public double Y_Position { get; set; }
[Column("y_velocity")]
public double Y_Velocity { get; set; }
[Key]
[Column("id")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public ulong Id { get; set; }
[Column("target_type")] // <--- This is the offending column
public TargetType TargetType { get; set; }
}
РЕДАКТИРОВАТЬ 2: Пересмотренный пример с рабочей вставкой.
Иллюстрация использования:
using Npgsql;
using Dapper.FastCrud;
...
NpgsqlConnection.MapEnumGlobally<TargetType>("public.targettype"); // ... (1)
OrmConfiguration.DefaultDialect = SqlDialect.PostgreSql;
(using NpgsqlConnection conn = ...) // Connect to database
{
var samples = conn.Find<Sample>(); // <--- This works correctly
foreach (Sample s in samples)
Console.WriteLine(s);
... // Generate new samples
using (var writer = conn.BeginBinaryImport(sql))
{
foreach (Sample s in entities)
{
writer.StartRow();
writer.Write(s.TargetType); // <--- This insert works, due to (1)
...
}
}
foreach (Sample sample in sampleList)
conn.Insert<Sample>(sample); // <--- This throws PostgresException
...
}
1 ответ
Я столкнулся с этой же проблемой сегодня, и я пришел к выводу, что Даппер в настоящее время просто не поддерживает это. То, что вы хотели бы сделать, это зарегистрировать обработчик пользовательского типа с SqlMapper
как это:
public class DbClass
{
static DbClass()
{
SqlMapper.AddTypeHandler(new MyPostgresEnumTypeHandler());
}
class MyPostgresEnumTypeHandler : SqlMapper.TypeHandler<MyPostgresEnum>
{
public override MyPostgresEnum Parse(object value)
{
switch (value)
{
case int i: return (MyPostgresEnum)i;
case string s: return (MyPostgresEnum)Enum.Parse(typeof(MyPostgresEnum),s);
default: throw new NotSupportedException($"{value} not a valid MyPostgresEnum value");
}
}
public override void SetValue(IDbDataParameter parameter, MyPostgresEnum value)
{
parameter.DbType = (DbType)NpgsqlDbType.Unknown;
// assuming the enum case names match the ones defined in Postgres
parameter.Value = Enum.GetName(typeof(MyPostgresEnum), (int)value).ToString().ToLowerInvariant();
}
}
}
К сожалению, это не работает, потому что Dapper игнорирует специальные обработчики типов для Enums, в частности. См. https://github.com/StackExchange/Dapper/issues/259 для получения подробной информации.
Мой подход в ожидании, чтобы увидеть, будет ли когда-либо решаться этот вопрос, будет писать NpgsqlCommand
запросы непосредственно при работе с этими видами перечислений.
Вы, вероятно, должны конвертировать TargetType в целое число.
Не проверено, но что-то вроде
Get
{
return (int)this.TargetType;
}