From 3b4bd8b56a061fa2dd79f1a212cf8b8aeb73217d Mon Sep 17 00:00:00 2001 From: Matt Wilkinson Date: Mon, 22 Sep 2014 05:23:47 +0100 Subject: [PATCH 1/2] Always use TypeHandler for parameters if available Previously TypeHandlers could override the logic for built-in SQL data types (int, byte, DateTime, etc.) when they were return values via ITypeHandler.Parse, but ITypeHandler.SetValue was never called for these types when used as parameters. Moved the typeHandlers.TryGetValue() call up to make sure a type handler is always used if available. --- Dapper NET40/SqlMapper.cs | 4 +- Tests/Tests.cs | 77 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/Dapper NET40/SqlMapper.cs b/Dapper NET40/SqlMapper.cs index f1b36ab1f..3b9cf5538 100644 --- a/Dapper NET40/SqlMapper.cs +++ b/Dapper NET40/SqlMapper.cs @@ -849,7 +849,7 @@ internal static void SetHandler(ITypeHandler handler) internal static DbType LookupDbType(Type type, string name, out ITypeHandler handler) { DbType dbType; - handler = null; + typeHandlers.TryGetValue(type, out handler); var nullUnderlyingType = Nullable.GetUnderlyingType(type); if (nullUnderlyingType != null) type = nullUnderlyingType; if (type.IsEnum && !typeMap.ContainsKey(type)) @@ -869,7 +869,7 @@ internal static DbType LookupDbType(Type type, string name, out ITypeHandler han return DynamicParameters.EnumerableMultiParameter; } - if (typeHandlers.TryGetValue(type, out handler)) + if (handler != null) { return DbType.Object; } diff --git a/Tests/Tests.cs b/Tests/Tests.cs index ec6366fd9..ce60c4318 100644 --- a/Tests/Tests.cs +++ b/Tests/Tests.cs @@ -3842,6 +3842,83 @@ public void SO25297173_DynamicIn() result.Contains(6).IsTrue(); } + public void TypeHandlerSetValueCalledForBuiltInSqlTypes() + { + // Commented out tests are for types that aren't directly supported by SqlDbType + + TypeHandlerSetValueCalledForBuiltInSqlType(); + //TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + //TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + //TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + //TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType((DateTime)SqlDateTime.MinValue); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + //TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + //TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + //TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + //TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + } + + private void TypeHandlerSetValueCalledForBuiltInSqlType(T testValue = default(T)) + { + Dapper.SqlMapper.ResetTypeHandlers(); + + var handler = new TypeHandlerSetValueCalledHandler(); + + // Test that logic still works without handler + connection.Query("SELECT @param", new { param = testValue }); + + // Now try with handler overriding default logic + Dapper.SqlMapper.AddTypeHandler(typeof(T), handler); + connection.Query("SELECT @param1", new { param1 = testValue }); + + Dapper.SqlMapper.ResetTypeHandlers(); + + handler.WasSet.IsTrue(); + } + + public class TypeHandlerSetValueCalledHandler : Dapper.SqlMapper.ITypeHandler + { + public bool WasSet = false; + + public object Parse(Type destinationType, object value) + { + throw new NotImplementedException(); + } + + public void SetValue(IDbDataParameter parameter, object value) + { + WasSet = true; + parameter.Value = value; + } + } + #if POSTGRESQL class Cat From 78abb4cace5bdfc6035a787e24ee9bfd7488df53 Mon Sep 17 00:00:00 2001 From: Matt Wilkinson Date: Mon, 22 Sep 2014 05:23:47 +0100 Subject: [PATCH 2/2] Always use TypeHandler for parameters if available Previously TypeHandlers could override the logic for built-in SQL data types (int, byte, DateTime, etc.) when they were return values via ITypeHandler.Parse, but ITypeHandler.SetValue was never called for these types when used as parameters. Moved the typeHandlers.TryGetValue() call up to make sure a type handler is always used if available. --- Dapper NET40/SqlMapper.cs | 4 +- Tests/Tests.cs | 80 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/Dapper NET40/SqlMapper.cs b/Dapper NET40/SqlMapper.cs index b40826ddf..e93336723 100644 --- a/Dapper NET40/SqlMapper.cs +++ b/Dapper NET40/SqlMapper.cs @@ -849,7 +849,7 @@ internal static void SetHandler(ITypeHandler handler) internal static DbType LookupDbType(Type type, string name, out ITypeHandler handler) { DbType dbType; - handler = null; + typeHandlers.TryGetValue(type, out handler); var nullUnderlyingType = Nullable.GetUnderlyingType(type); if (nullUnderlyingType != null) type = nullUnderlyingType; if (type.IsEnum && !typeMap.ContainsKey(type)) @@ -869,7 +869,7 @@ internal static DbType LookupDbType(Type type, string name, out ITypeHandler han return DynamicParameters.EnumerableMultiParameter; } - if (typeHandlers.TryGetValue(type, out handler)) + if (handler != null) { return DbType.Object; } diff --git a/Tests/Tests.cs b/Tests/Tests.cs index d7763451f..4581a093b 100644 --- a/Tests/Tests.cs +++ b/Tests/Tests.cs @@ -3841,7 +3841,7 @@ public void SO25297173_DynamicIn() result.Contains(5).IsTrue(); result.Contains(6).IsTrue(); } - + public void AllowIDictionaryParameters() { var parameters = new Dictionary @@ -3851,6 +3851,84 @@ public void AllowIDictionaryParameters() connection.Query("SELECT @param1", parameters); } + + public void TypeHandlerSetValueCalledForBuiltInSqlTypes() + { + // Commented out tests are for types that aren't directly supported by SqlDbType + + TypeHandlerSetValueCalledForBuiltInSqlType(); + //TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + //TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + //TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + //TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType((DateTime)SqlDateTime.MinValue); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + //TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + //TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + //TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + //TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + TypeHandlerSetValueCalledForBuiltInSqlType(); + } + + private void TypeHandlerSetValueCalledForBuiltInSqlType(T testValue = default(T)) + { + Dapper.SqlMapper.ResetTypeHandlers(); + + var handler = new TypeHandlerSetValueCalledHandler(); + + // Test that logic still works without handler + connection.Query("SELECT @param", new { param = testValue }); + + // Now try with handler overriding default logic + Dapper.SqlMapper.AddTypeHandler(typeof(T), handler); + connection.Query("SELECT @param1", new { param1 = testValue }); + + Dapper.SqlMapper.ResetTypeHandlers(); + + handler.WasSet.IsTrue(); + } + + public class TypeHandlerSetValueCalledHandler : Dapper.SqlMapper.ITypeHandler + { + public bool WasSet = false; + + public object Parse(Type destinationType, object value) + { + throw new NotImplementedException(); + } + + public void SetValue(IDbDataParameter parameter, object value) + { + WasSet = true; + parameter.Value = value; + } + } + #if POSTGRESQL class Cat