2014-11-24 105 views
7

我试图使用Dapper连接到一个现有的数据库格式,该数据库格式的表格的持续时间编码为BIGINT列中的勾号。在插入和读取数据库时,如何告诉Dapper将POCO的TimeSpan-type属性映射为ticks?在SQLite和Dapper中映射TimeSpan

我试着设置类型映射TimeSpanDbType.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; 
    } 
} 

这里的我的POCO:

public class Task 
{ 
    public TimeSpan Duration { get; set; } 

    // etc. 
} 

Wh EN执行一个简单的插入语句是这样的:

string sql = "INSERT INTO Tasks (Duration) values (@Duration);"; 

并传递POCO作为要插入的对象:如果我离开TimeSpan

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 

Task task = new Task { Duration = TimeSpan.FromSeconds(20) }; 
connection.Execute(sql, task); 

我得到这个例外(默认为DbType.Time),它会写入TimeSpan的字符串版本,即'00:00:20.000',这是没有用的,因为它不匹配fo列中其他数据的rmat。

+0

我总是通过创建,做翻译的第二属性解决了这个从数据库类型到我的类型。 – juharr 2014-11-24 16:44:03

+0

为什么downvote ...? – 2014-11-24 16:52:45

回答

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);"; 
+0

我可以,虽然作为一个Dapper新手,我希望有一些图书馆提供的东西。似乎应该有所有的'ITypeHandler'和其他这样的接口...... – 2014-11-24 16:51:39

1

解决方案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([email protected]"Id: {category.Id}, Time: {category.Time}"); 
     } 
    } 

    private class Category 
    { 
     public int Id { get; set; } 
     public TimeSpan Time { get; set; } 
    } 
}