2014-11-24 17 views
7

Ich versuche, Dapper Schnittstelle zu einem vorhandenen Datenbankformat zu verwenden, das eine Tabelle mit einer Dauer aufweist, die als Ticks in einer BIGINT-Spalte codiert wird. Wie sage ich Dapper, um die TimeSpan-type-Eigenschaft meines POCO Ticks zuzuordnen, wenn es in die Datenbank eingefügt wird und von der Datenbank liest?Mapping TimeSpan in SQLite und Dapper

Ich habe versucht, den Typ der Karte für TimeSpan-DbType.Int64 einzustellen:

SqlMapper.AddTypeMap(typeof(TimeSpan), DbType.Int64); 

Und ich habe erstellt auch eine ITypeHandler, aber die SetValue Methode aufgerufen wird nie:

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; 
    } 
} 

Hier mein POCO:

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

    // etc. 
} 

Wh en eine einfache Insert-Anweisung wie folgt ausführen:

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

Und die POCO als Objekt vorbei einzufügen:

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

Ich erhalte diese Ausnahme:

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 

Wenn ich die TimeSpan verlassen Typ Mapping wie es ist (es ist standardmäßig DbType.Time), es schreibt die String-Version der TimeSpan, dh `00: 00: 20.000", was nicht hilfreich ist, da es nicht die fo entspricht rmat der anderen Daten in der Spalte.

+0

Ich habe immer dieses Problem gelöst, indem eine zweite Eigenschaft erstellen, die die Übersetzung tut vom DB-Typ zu meinem Typ. – juharr

+0

Warum der Downvote ...? –

Antwort

2

Können Sie stattdessen Folgendes tun?

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

Ich konnte, obwohl ich als Dapper Neuling hoffte, dass es etwas gab, was die Bibliothek zur Verfügung stellte. Es scheint so, als müsste es bei allen ITypeHandler und anderen solchen Schnittstellen ... –

1

Lösungen für LinqToDB:

MappingSchema.SetDataType(typeof(TimeSpan), DataType.NText); 

Oder:

MappingSchema.SetDataType(typeof(TimeSpan), DataType.Int64); 

Beispiel:

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; } 
    } 
}