Commit 49e797a4 authored by Marc Gravell's avatar Marc Gravell

Fix #461 - change FindConstructor to allow parameters that have a type-handler defined

parent 1797a3c0
...@@ -138,71 +138,79 @@ public void TestNoDefaultConstructorBinary() ...@@ -138,71 +138,79 @@ public void TestNoDefaultConstructorBinary()
[Fact] [Fact]
public void Issue461_TypeHandlerWorksInConstructor() public void Issue461_TypeHandlerWorksInConstructor()
{ {
// SqlMapper.AddTypeHandler(new Issue461_DateTimeOffsetHandler()); SqlMapper.AddTypeHandler(new Issue461_BlargHandler());
connection.Execute(@"CREATE TABLE #Issue461 ( connection.Execute(@"CREATE TABLE #Issue461 (
Id VARCHAR(50), Id int not null IDENTITY(1,1),
SomeValue VARCHAR(50), SomeValue nvarchar(50),
SomeDateValue DATETIMEOFFSET SomeBlargValue nvarchar(200),
)"); )");
var when = new DateTimeOffset(2016, 02, 15, 16, 0, 0, TimeSpan.FromHours(2)); const string Expected = "abc123def";
var blarg = new Blarg(Expected);
connection.Execute( connection.Execute(
"INSERT INTO #Issue461 (Id, SomeValue, SomeDateValue) VALUES (@Id, @SomeValue, @SomeDateValue)", "INSERT INTO #Issue461 (SomeValue, SomeBlargValue) VALUES (@value, @blarg)",
new new { value = "what up?", blarg });
{
Id = "id",
SomeValue = "what up?",
SomeDateValue = when
});
// test: without constructor
var parameterlessWorks = connection.QuerySingle<Issue461_ParameterlessTypeConstructor>("SELECT * FROM #Issue461"); var parameterlessWorks = connection.QuerySingle<Issue461_ParameterlessTypeConstructor>("SELECT * FROM #Issue461");
parameterlessWorks.Id.IsEqualTo("id"); parameterlessWorks.Id.IsEqualTo(1);
parameterlessWorks.SomeValue.IsEqualTo("what up?"); parameterlessWorks.SomeValue.IsEqualTo("what up?");
parameterlessWorks.SomeDateValue.IsEqualTo(when); parameterlessWorks.SomeBlargValue.Value.IsEqualTo(Expected);
//throws about not being able to find constructor (It expects the DateTime field to be a string still) // test: via constructor
var parameterDoesNot = connection.QuerySingle<Issue461_ParameterisedTypeConstructor>("SELECT * FROM #Issue461"); var parameterDoesNot = connection.QuerySingle<Issue461_ParameterisedTypeConstructor>("SELECT * FROM #Issue461");
parameterDoesNot.Id.IsEqualTo("id"); parameterDoesNot.Id.IsEqualTo(1);
parameterDoesNot.SomeValue.IsEqualTo("what up?"); parameterDoesNot.SomeValue.IsEqualTo("what up?");
parameterDoesNot.SomeDateValue.IsEqualTo(when); parameterDoesNot.SomeBlargValue.Value.IsEqualTo(Expected);
} }
//class Issue461_DateTimeOffsetHandler : SqlMapper.TypeHandler<DateTimeOffset> class Blarg // I would usually expect this to be a struct; using a class
//{ { // so that we can't pass unexpectedly due to forcing an unsafe cast - want
// public override void SetValue(IDbDataParameter parameter, DateTimeOffset value) // to see an InvalidCastException if it is wrong
// { public Blarg(string value) { Value = value; }
// parameter.Value = value.ToString(); public string Value { get; }
// } public override string ToString()
{
return Value;
}
}
class Issue461_BlargHandler : SqlMapper.TypeHandler<Blarg>
{
public override void SetValue(IDbDataParameter parameter, Blarg value)
{
parameter.Value = ((object)value.Value) ?? DBNull.Value;
}
// public override DateTimeOffset Parse(object value) public override Blarg Parse(object value)
// { {
// return DateTimeOffset.Parse(value.ToString()); string s = (value == null || value is DBNull) ? null : Convert.ToString(value);
// } return new Blarg(s);
//} }
}
class Issue461_ParameterlessTypeConstructor class Issue461_ParameterlessTypeConstructor
{ {
public string Id { get; set; } public int Id { get; set; }
public string SomeValue { get; set; } public string SomeValue { get; set; }
public DateTimeOffset SomeDateValue { get; set; } public Blarg SomeBlargValue { get; set; }
} }
class Issue461_ParameterisedTypeConstructor class Issue461_ParameterisedTypeConstructor
{ {
public Issue461_ParameterisedTypeConstructor(string id, string someValue, DateTimeOffset someDateValue) public Issue461_ParameterisedTypeConstructor(int id, string someValue, Blarg someBlargValue)
{ {
Id = id; Id = id;
SomeValue = someValue; SomeValue = someValue;
SomeDateValue = someDateValue; SomeBlargValue = someBlargValue;
} }
public string Id { get; } public int Id { get; }
public string SomeValue { get; } public string SomeValue { get; }
public DateTimeOffset SomeDateValue { get; } public Blarg SomeBlargValue { get; }
} }
public class AbstractInheritance public class AbstractInheritance
......
...@@ -96,7 +96,7 @@ public ConstructorInfo FindConstructor(string[] names, Type[] types) ...@@ -96,7 +96,7 @@ public ConstructorInfo FindConstructor(string[] names, Type[] types)
if (types[i] == typeof(byte[]) && ctorParameters[i].ParameterType.FullName == SqlMapper.LinqBinary) if (types[i] == typeof(byte[]) && ctorParameters[i].ParameterType.FullName == SqlMapper.LinqBinary)
continue; continue;
var unboxedType = Nullable.GetUnderlyingType(ctorParameters[i].ParameterType) ?? ctorParameters[i].ParameterType; var unboxedType = Nullable.GetUnderlyingType(ctorParameters[i].ParameterType) ?? ctorParameters[i].ParameterType;
if (unboxedType != types[i] if ((unboxedType != types[i] && !SqlMapper.HasTypeHandler(unboxedType))
&& !(unboxedType.IsEnum() && Enum.GetUnderlyingType(unboxedType) == types[i]) && !(unboxedType.IsEnum() && Enum.GetUnderlyingType(unboxedType) == types[i])
&& !(unboxedType == typeof(char) && types[i] == typeof(string)) && !(unboxedType == typeof(char) && types[i] == typeof(string))
&& !(unboxedType.IsEnum() && types[i] == typeof(string))) && !(unboxedType.IsEnum() && types[i] == typeof(string)))
......
...@@ -270,6 +270,11 @@ public static void AddTypeHandler(Type type, ITypeHandler handler) ...@@ -270,6 +270,11 @@ public static void AddTypeHandler(Type type, ITypeHandler handler)
AddTypeHandlerImpl(type, handler, true); AddTypeHandlerImpl(type, handler, true);
} }
internal static bool HasTypeHandler(Type type)
{
return typeHandlers.ContainsKey(type);
}
/// <summary> /// <summary>
/// Configure the specified type to be processed by a custom handler /// Configure the specified type to be processed by a custom handler
/// </summary> /// </summary>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment