Skip to content

Commit

Permalink
Fix #461 - change FindConstructor to allow parameters that have a typ…
Browse files Browse the repository at this point in the history
…e-handler defined
  • Loading branch information
mgravell committed Feb 17, 2016
1 parent 1797a3c commit 49e797a
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 35 deletions.
76 changes: 42 additions & 34 deletions Dapper.Tests/Tests.Constructors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,71 +138,79 @@ public void TestNoDefaultConstructorBinary()
[Fact]
public void Issue461_TypeHandlerWorksInConstructor()
{
// SqlMapper.AddTypeHandler(new Issue461_DateTimeOffsetHandler());
SqlMapper.AddTypeHandler(new Issue461_BlargHandler());

connection.Execute(@"CREATE TABLE #Issue461 (
Id VARCHAR(50),
SomeValue VARCHAR(50),
SomeDateValue DATETIMEOFFSET
Id int not null IDENTITY(1,1),
SomeValue nvarchar(50),
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(
"INSERT INTO #Issue461 (Id, SomeValue, SomeDateValue) VALUES (@Id, @SomeValue, @SomeDateValue)",
new
{
Id = "id",
SomeValue = "what up?",
SomeDateValue = when
});
"INSERT INTO #Issue461 (SomeValue, SomeBlargValue) VALUES (@value, @blarg)",
new { value = "what up?", blarg });

// test: without constructor
var parameterlessWorks = connection.QuerySingle<Issue461_ParameterlessTypeConstructor>("SELECT * FROM #Issue461");
parameterlessWorks.Id.IsEqualTo("id");
parameterlessWorks.Id.IsEqualTo(1);
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");
parameterDoesNot.Id.IsEqualTo("id");
parameterDoesNot.Id.IsEqualTo(1);
parameterDoesNot.SomeValue.IsEqualTo("what up?");
parameterDoesNot.SomeDateValue.IsEqualTo(when);
parameterDoesNot.SomeBlargValue.Value.IsEqualTo(Expected);


}

//class Issue461_DateTimeOffsetHandler : SqlMapper.TypeHandler<DateTimeOffset>
//{
// public override void SetValue(IDbDataParameter parameter, DateTimeOffset value)
// {
// parameter.Value = value.ToString();
// }
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
// to see an InvalidCastException if it is wrong
public Blarg(string value) { Value = value; }
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)
// {
// return DateTimeOffset.Parse(value.ToString());
// }
//}
public override Blarg Parse(object value)
{
string s = (value == null || value is DBNull) ? null : Convert.ToString(value);
return new Blarg(s);
}
}

class Issue461_ParameterlessTypeConstructor
{
public string Id { get; set; }
public int Id { get; set; }

public string SomeValue { get; set; }
public DateTimeOffset SomeDateValue { get; set; }
public Blarg SomeBlargValue { get; set; }
}

class Issue461_ParameterisedTypeConstructor
{
public Issue461_ParameterisedTypeConstructor(string id, string someValue, DateTimeOffset someDateValue)
public Issue461_ParameterisedTypeConstructor(int id, string someValue, Blarg someBlargValue)
{
Id = id;
SomeValue = someValue;
SomeDateValue = someDateValue;
SomeBlargValue = someBlargValue;
}

public string Id { get; }
public int Id { get; }

public string SomeValue { get; }
public DateTimeOffset SomeDateValue { get; }
public Blarg SomeBlargValue { get; }
}

public class AbstractInheritance
Expand Down
2 changes: 1 addition & 1 deletion Dapper/DefaultTypeMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public ConstructorInfo FindConstructor(string[] names, Type[] types)
if (types[i] == typeof(byte[]) && ctorParameters[i].ParameterType.FullName == SqlMapper.LinqBinary)
continue;
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 == typeof(char) && types[i] == typeof(string))
&& !(unboxedType.IsEnum() && types[i] == typeof(string)))
Expand Down
5 changes: 5 additions & 0 deletions Dapper/SqlMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,11 @@ public static void AddTypeHandler(Type type, ITypeHandler handler)
AddTypeHandlerImpl(type, handler, true);
}

internal static bool HasTypeHandler(Type type)
{
return typeHandlers.ContainsKey(type);
}

/// <summary>
/// Configure the specified type to be processed by a custom handler
/// </summary>
Expand Down

0 comments on commit 49e797a

Please sign in to comment.