2014-11-24 49 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; } 
    } 
}