-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Description
We've had to create a TypeHandler to handle DateTimeOffset because SQLite has no concept of date/time, so it is saved as a string, which is fine. When querying the data back out, the Parse method is only called if it is being serialised to a type with a parameterless constructor. If a constructor exists which initialises all the properties the type handler is not called, which results in a "InvalidOperationException" with the following
A parameterless default constructor or one matching signature (System.String Id, System.String SomeValue, System.String SomeDateValue) is required for DapperTypeHandler.ParameterisedTypeConstructor materialization
Note how it is looking for SomeDateValue to be a string still.
I'm not sure if I'm explaining this the best way, I haven't been using Dapper for very long, so this may not be the best way of solving this problem. Below is a small, reproducible example using an in memory SQLite database.
using System;
using System.Data;
using System.Data.SQLite;
using Dapper;
namespace DapperTypeHandler
{
class Program
{
static void Main(string[] args)
{
SqlMapper.AddTypeHandler(new DateTimeOffsetHandler());
var dbConnection = new SQLiteConnection("Data Source=:memory:");
dbConnection.Open();
dbConnection.Execute(@"CREATE TABLE SomeTable (
Id VARCHAR,
SomeValue VARCHAR,
SomeDateValue DATETIMEOFFSET
)");
dbConnection.Execute(
"INSERT INTO SomeTable (Id, SomeValue, SomeDateValue) VALUES (@Id, @SomeValue, @SomeDateValue)",
new
{
Id = "id",
SomeValue = "what up?",
SomeDateValue = new DateTimeOffset(2016, 02, 15, 16, 0, 0, TimeSpan.Zero)
});
var parameterlessWorks = dbConnection.Query<ParameterlessTypeConstructor>("SELECT * FROM SomeTable");
//throws about not being able to find constructor (It expects the DateTime field to be a string still)
var parameterDoesNot = dbConnection.Query<ParameterisedTypeConstructor>("SELECT * FROM SomeTable");
}
}
class DateTimeOffsetHandler : SqlMapper.TypeHandler<DateTimeOffset>
{
public override void SetValue(IDbDataParameter parameter, DateTimeOffset value)
{
parameter.Value = value.ToString();
}
public override DateTimeOffset Parse(object value)
{
return DateTimeOffset.Parse(value.ToString());
}
}
class ParameterlessTypeConstructor
{
public string Id { get; set; }
public string SomeValue { get; set; }
public DateTimeOffset SomeDateValue { get; set; }
}
class ParameterisedTypeConstructor
{
public ParameterisedTypeConstructor(string id, string someValue, DateTimeOffset someDateValue)
{
Id = id;
SomeValue = someValue;
SomeDateValue = someDateValue;
}
public string Id { get; set; }
public string SomeValue { get; set; }
public DateTimeOffset SomeDateValue { get; set; }
}
}