Я пытаюсь использовать Dapper для взаимодействия с существующим форматом базы данных, в котором есть таблица с продолжительностью, закодированной как тики в столбце BIGINT. Как указать Dapper сопоставлять свойство типа TimeSpan
моего POCO с тиками при вставке в базу данных и чтении из нее?
Я попытался установить карту типов для TimeSpan
на DbType.Int64
:
SqlMapper.AddTypeMap(typeof(TimeSpan), DbType.Int64);
И я также создал ITypeHandler
, но метод SetValue
никогда не вызывается:
public class TimeSpanToTicksHandler : SqlMapper.TypeHandler<TimeSpan>
{
public override TimeSpan Parse(object value)
{
return new TimeSpan((long)value);
}
public override void SetValue(IDbDataParameter parameter, TimeSpan value)
{
parameter.Value = value.Ticks;
}
}
Вот мой ПОКО:
public class Task
{
public TimeSpan Duration { get; set; }
// etc.
}
При выполнении простого оператора вставки, подобного этому:
string sql = "INSERT INTO Tasks (Duration) values (@Duration);";
И передача POCO в качестве объекта для вставки:
Task task = new Task { Duration = TimeSpan.FromSeconds(20) };
connection.Execute(sql, task);
Я получаю это исключение:
System.InvalidCastException : Unable to cast object of type 'System.TimeSpan' to type 'System.IConvertible'.
at System.Convert.ToInt64(Object value, IFormatProvider provider)
at System.Data.SQLite.SQLiteStatement.BindParameter(Int32 index, SQLiteParameter param)
at System.Data.SQLite.SQLiteStatement.BindParameters()
at System.Data.SQLite.SQLiteCommand.BuildNextCommand()
at System.Data.SQLite.SQLiteCommand.GetStatement(Int32 index)
at System.Data.SQLite.SQLiteDataReader.NextResult()
at System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave)
at System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior)
at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery(CommandBehavior behavior)
at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery()
at Dapper.SqlMapper.ExecuteCommand(IDbConnection cnn, ref CommandDefinition command, Action`2 paramReader) in SqlMapper.cs: line 3310
at Dapper.SqlMapper.ExecuteImpl(IDbConnection cnn, ref CommandDefinition command) in SqlMapper.cs: line 1310
at Dapper.SqlMapper.Execute(IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Nullable`1 commandTimeout, Nullable`1 commandType) in SqlMapper.cs: line 1185
Если я оставлю сопоставление типа TimeSpan
как есть (по умолчанию DbType.Time
), будет записана строковая версия TimeSpan
, т.е. `00:00:20.000", что бесполезно, так как не соответствует формату других данных в столбце.
2 ответа
Не могли бы вы сделать следующее вместо этого?
public class Task
{
public TimeSpan Duration { get; set; }
public long Ticks
{
get { return Duration.Ticks; }
set { Duration = new TimeSpan(value); }
}
// etc.
}
string sql = "INSERT INTO Tasks (Duration) values (@Ticks);";
ITypeHandler
и прочими такими интерфейсами...
Решения для LinqToDB:
MappingSchema.SetDataType(typeof(TimeSpan), DataType.NText);
Или же:
MappingSchema.SetDataType(typeof(TimeSpan), DataType.Int64);
Примере:
public class Program
{
private const string ConnectionString = "Data Source=:memory:;Version=3;New=True;";
public static void Main()
{
var dataProvider = new SQLiteDataProvider();
var connection = dataProvider.CreateConnection(ConnectionString);
connection.Open();
var dataConnection = new DataConnection(dataProvider, connection);
dataConnection.MappingSchema.SetDataType(typeof(TimeSpan), DataType.Int64);
dataConnection.CreateTable<Category>();
dataConnection.GetTable<Category>()
.DataContextInfo
.DataContext
.Insert(new Category
{
Id = 2,
Time = new TimeSpan(10, 0, 0)
});
foreach (var category in dataConnection.GetTable<Category>())
{
Console.WriteLine($@"Id: {category.Id}, Time: {category.Time}");
}
}
private class Category
{
public int Id { get; set; }
public TimeSpan Time { get; set; }
}
}
MappingSchema.SetDataType(typeof(TimeSpan), DataType.NText);
это не удается при вставке с ошибкойMappingSchema.SetDataType(typeof(TimeSpan), DataType.Int64);
работает для вставки, но вызывает исключение при выборе System.FormatException: String was not recognized as a valid DateTime.
dataConnection.MappingSchema.SetDataType(typeof(TimeSpan), DataType.Int64);
должен выполняться для каждого нового экземпляра соединения. Я пытался установить его один раз как LinqToDB.Mapping.MappingSchema.Default.SetDataType(typeof(TimeSpan), DataType.Int64)
, но не повезло
Похожие вопросы
Новые вопросы
c#
C# (произносится как «see Sharp») — это высокоуровневый мультипарадигменный язык программирования со статической типизацией, разработанный Microsoft. Код C# обычно нацелен на семейство инструментов и сред выполнения Microsoft .NET, которое включает в себя .NET, .NET Framework, .NET MAUI и Xamarin среди прочих. Используйте этот тег для ответов на вопросы о коде, написанном на C#, или о формальной спецификации C#.