Commit 19ac29d8 authored by mgravell's avatar mgravell

fix TVP vs UDT - different setup

parent ee7c65aa
...@@ -40,37 +40,42 @@ void SqlMapper.ICustomQueryParameter.AddParameter(IDbCommand command, string nam ...@@ -40,37 +40,42 @@ void SqlMapper.ICustomQueryParameter.AddParameter(IDbCommand command, string nam
internal static void Set(IDbDataParameter parameter, IEnumerable<T> data, string typeName) internal static void Set(IDbDataParameter parameter, IEnumerable<T> data, string typeName)
{ {
parameter.Value = data != null && data.Any() ? data : null; parameter.Value = data != null && data.Any() ? data : null;
StructuredHelper.ConfigureStructured(parameter, typeName); StructuredHelper.ConfigureTVP(parameter, typeName);
} }
} }
static class StructuredHelper static class StructuredHelper
{ {
private static readonly Hashtable s_perTypeHelpers = new Hashtable(); private static readonly Hashtable s_udt = new Hashtable(), s_tvp = new Hashtable();
private static Action<IDbDataParameter, string> GetHelper(Type type)
=> (Action<IDbDataParameter, string>)s_perTypeHelpers[type] ?? SlowGetHelper(type); private static Action<IDbDataParameter, string> GetUDT(Type type)
static Action<IDbDataParameter, string> SlowGetHelper(Type type) => (Action<IDbDataParameter, string>)s_udt[type] ?? SlowGetHelper(type, s_udt, "UdtTypeName", 29); // 29 = SqlDbType.Udt (avoiding ref)
private static Action<IDbDataParameter, string> GetTVP(Type type)
=> (Action<IDbDataParameter, string>)s_tvp[type] ?? SlowGetHelper(type, s_tvp, "TypeName", 30); // 30 = SqlDbType.Structured (avoiding ref)
static Action<IDbDataParameter, string> SlowGetHelper(Type type, Hashtable hashtable, string nameProperty, int sqlDbType)
{ {
lock(s_perTypeHelpers) lock (hashtable)
{ {
var helper = (Action<IDbDataParameter, string>)s_perTypeHelpers[type]; var helper = (Action<IDbDataParameter, string>)hashtable[type];
if (helper == null) if (helper == null)
{ {
helper = CreateFor(type); helper = CreateFor(type, nameProperty, sqlDbType);
s_perTypeHelpers.Add(type, helper); hashtable.Add(type, helper);
} }
return helper; return helper;
} }
} }
static Action<IDbDataParameter, string> CreateFor(Type type)
{
//return (p, n) => { };
var name = type.GetProperty("TypeName", BindingFlags.Public | BindingFlags.Instance); static Action<IDbDataParameter, string> CreateFor(Type type, string nameProperty, int sqlDbType)
if (!name.CanWrite) name = null; {
if (name == null) return (p, n) => { }; var name = type.GetProperty(nameProperty, BindingFlags.Public | BindingFlags.Instance);
if (name == null || !name.CanWrite)
{
return (p, n) => { };
}
var dbType = type.GetProperty("SqlDbType", BindingFlags.Public | BindingFlags.Instance); var dbType = type.GetProperty("SqlDbType", BindingFlags.Public | BindingFlags.Instance);
if (!dbType.CanWrite) dbType = null; if (dbType != null && !dbType.CanWrite) dbType = null;
var dm = new DynamicMethod(nameof(CreateFor) + "_" + type.Name, null, var dm = new DynamicMethod(nameof(CreateFor) + "_" + type.Name, null,
new[] { typeof(IDbDataParameter), typeof(string) }, true); new[] { typeof(IDbDataParameter), typeof(string) }, true);
...@@ -84,11 +89,7 @@ static class StructuredHelper ...@@ -84,11 +89,7 @@ static class StructuredHelper
{ {
il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, type); il.Emit(OpCodes.Castclass, type);
#if NETSTANDARD1_3 il.Emit(OpCodes.Ldc_I4, sqlDbType);
il.Emit(OpCodes.Ldc_I4, (int)30); // hard-code the known enum value
#else
il.Emit(OpCodes.Ldc_I4, (int)SqlDbType.Structured);
#endif
il.EmitCall(OpCodes.Callvirt, dbType.GetSetMethod(), null); il.EmitCall(OpCodes.Callvirt, dbType.GetSetMethod(), null);
} }
...@@ -99,7 +100,9 @@ static class StructuredHelper ...@@ -99,7 +100,9 @@ static class StructuredHelper
// this needs to be done per-provider; "dynamic" doesn't work well on all runtimes, although that // this needs to be done per-provider; "dynamic" doesn't work well on all runtimes, although that
// would be a fair option otherwise // would be a fair option otherwise
internal static void ConfigureStructured(IDbDataParameter parameter, string typeName) internal static void ConfigureUDT(IDbDataParameter parameter, string typeName)
=> GetHelper(parameter.GetType())(parameter, typeName); => GetUDT(parameter.GetType())(parameter, typeName);
internal static void ConfigureTVP(IDbDataParameter parameter, string typeName)
=> GetTVP(parameter.GetType())(parameter, typeName);
} }
} }
using System; using System.Data;
using System.Data;
using System.Reflection;
#if !NETSTANDARD1_3 #if !NETSTANDARD1_3
namespace Dapper namespace Dapper
...@@ -47,7 +45,7 @@ internal static void Set(IDbDataParameter parameter, DataTable table, string typ ...@@ -47,7 +45,7 @@ internal static void Set(IDbDataParameter parameter, DataTable table, string typ
{ {
typeName = table.GetTypeName(); typeName = table.GetTypeName();
} }
if (!string.IsNullOrEmpty(typeName)) StructuredHelper.ConfigureStructured(parameter, typeName); if (!string.IsNullOrEmpty(typeName)) StructuredHelper.ConfigureTVP(parameter, typeName);
} }
} }
} }
......
...@@ -33,7 +33,7 @@ void ITypeHandler.SetValue(IDbDataParameter parameter, object value) ...@@ -33,7 +33,7 @@ void ITypeHandler.SetValue(IDbDataParameter parameter, object value)
#pragma warning disable 0618 #pragma warning disable 0618
parameter.Value = SanitizeParameterValue(value); parameter.Value = SanitizeParameterValue(value);
#pragma warning restore 0618 #pragma warning restore 0618
if(!(value is DBNull)) StructuredHelper.ConfigureStructured(parameter, udtTypeName); if(!(value is DBNull)) StructuredHelper.ConfigureUDT(parameter, udtTypeName);
} }
} }
#endif #endif
......
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