2014-11-24 11 views
7

Próbuję użyć Dapper do interfejsu do istniejącego formatu bazy danych, który ma tabelę z czasem zakodowanym jako tyknięcia w kolumnie BIGINT. W jaki sposób mogę powiedzieć Dapperowi, aby zmapował moją właściwość POCO na TimeSpan -typed podczas wstawiania i odczytu z bazy danych?Timeapan mapowania w SQLite i Dapper

Próbowałem ustawić mapę na TimeSpan do DbType.Int64:

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

A ja też stworzył ITypeHandler, ale metoda SetValue nigdy nie nazywa się:

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

Oto my POCO:

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

    // etc. 
} 

Wh pl wykonywania prostych instrukcji insert takiego:

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

i zdanie poco jako obiekt do wstawienia:

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

otrzymuję ten wyjątek:

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 

Gdybym opuścić TimeSpan mapowanie typu tak jak jest (domyślnie jest to DbType.Time), zapisuje ciąg znaków TimeSpan, tj. `00: 00: 20.000", co nie jest pomocne, ponieważ nie pasuje do rmat pozostałych danych w kolumnie.

+0

zawsze rozwiązać ten tworząc drugą właściwość, że robi tłumaczenie od typu DB do mojego typu. – juharr

+0

Dlaczego spadł ...? –

Odpowiedz

2

Czy zamiast tego można wykonać następujące czynności?

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

Mogłem, choć jako początkujący nowicjusz, mieć nadzieję, że jest coś, co zapewniła biblioteka. Wygląda na to, że powinno być ze wszystkimi "ITypeHandler" i innymi takimi interfejsami ... –

1

Rozwiązania dla LinqToDB:

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

Albo:

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

Przykład:

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