diff --git a/Dapper/DynamicParameters.cs b/Dapper/DynamicParameters.cs
index dc4f5a36..2569a938 100644
--- a/Dapper/DynamicParameters.cs
+++ b/Dapper/DynamicParameters.cs
@@ -155,6 +155,12 @@ namespace Dapper
///
public bool RemoveUnused { get; set; }
+ internal static bool ShouldSetDbType(DbType? dbType)
+ => dbType.HasValue && dbType.GetValueOrDefault() != EnumerableMultiParameter;
+
+ internal static bool ShouldSetDbType(DbType dbType)
+ => dbType != EnumerableMultiParameter; // just in case called with non-nullable
+
///
/// Add all the parameters needed to the command just before it executes
///
@@ -262,9 +268,9 @@ namespace Dapper
#pragma warning disable 0618
p.Value = SqlMapper.SanitizeParameterValue(val);
#pragma warning restore 0618
- if (dbType != null && p.DbType != dbType)
+ if (ShouldSetDbType(dbType) && p.DbType != dbType.GetValueOrDefault())
{
- p.DbType = dbType.Value;
+ p.DbType = dbType.GetValueOrDefault();
}
var s = val as string;
if (s?.Length <= DbString.DefaultLength)
@@ -277,7 +283,7 @@ namespace Dapper
}
else
{
- if (dbType != null) p.DbType = dbType.Value;
+ if (ShouldSetDbType(dbType)) p.DbType = dbType.GetValueOrDefault();
if (param.Size != null) p.Size = param.Size.Value;
if (param.Precision != null) p.Precision = param.Precision.Value;
if (param.Scale != null) p.Scale = param.Scale.Value;
@@ -468,15 +474,9 @@ namespace Dapper
}
else
{
- dbType = (!dbType.HasValue)
-#pragma warning disable 618
- ? SqlMapper.LookupDbType(targetMemberType, targetMemberType?.Name, true, out SqlMapper.ITypeHandler handler)
-#pragma warning restore 618
- : dbType;
-
// CameFromTemplate property would not apply here because this new param
// Still needs to be added to the command
- Add(dynamicParamName, expression.Compile().Invoke(target), null, ParameterDirection.InputOutput, sizeToSet);
+ Add(dynamicParamName, expression.Compile().Invoke(target), dbType, ParameterDirection.InputOutput, sizeToSet);
}
parameter = parameters[dynamicParamName];
diff --git a/Dapper/SqlMapper.cs b/Dapper/SqlMapper.cs
index 5ace2cbe..ee49c2ab 100644
--- a/Dapper/SqlMapper.cs
+++ b/Dapper/SqlMapper.cs
@@ -163,11 +163,11 @@ namespace Dapper
select Tuple.Create(pair.Key, pair.Value);
}
- private static Dictionary typeMap;
+ private static Dictionary typeMap;
static SqlMapper()
{
- typeMap = new Dictionary(37)
+ typeMap = new Dictionary(37)
{
[typeof(byte)] = DbType.Byte,
[typeof(sbyte)] = DbType.SByte,
@@ -184,9 +184,9 @@ namespace Dapper
[typeof(string)] = DbType.String,
[typeof(char)] = DbType.StringFixedLength,
[typeof(Guid)] = DbType.Guid,
- [typeof(DateTime)] = DbType.DateTime,
+ [typeof(DateTime)] = null,
[typeof(DateTimeOffset)] = DbType.DateTimeOffset,
- [typeof(TimeSpan)] = DbType.Time,
+ [typeof(TimeSpan)] = null,
[typeof(byte[])] = DbType.Binary,
[typeof(byte?)] = DbType.Byte,
[typeof(sbyte?)] = DbType.SByte,
@@ -202,9 +202,9 @@ namespace Dapper
[typeof(bool?)] = DbType.Boolean,
[typeof(char?)] = DbType.StringFixedLength,
[typeof(Guid?)] = DbType.Guid,
- [typeof(DateTime?)] = DbType.DateTime,
+ [typeof(DateTime?)] = null,
[typeof(DateTimeOffset?)] = DbType.DateTimeOffset,
- [typeof(TimeSpan?)] = DbType.Time,
+ [typeof(TimeSpan?)] = null,
[typeof(object)] = DbType.Object
};
ResetTypeHandlers(false);
@@ -234,9 +234,9 @@ namespace Dapper
// use clone, mutate, replace to avoid threading issues
var snapshot = typeMap;
- if (snapshot.TryGetValue(type, out DbType oldValue) && oldValue == dbType) return; // nothing to do
+ if (snapshot.TryGetValue(type, out var oldValue) && oldValue == dbType) return; // nothing to do
- typeMap = new Dictionary(snapshot) { [type] = dbType };
+ typeMap = new Dictionary(snapshot) { [type] = dbType };
}
///
@@ -250,7 +250,7 @@ namespace Dapper
if (!snapshot.ContainsKey(type)) return; // nothing to do
- var newCopy = new Dictionary(snapshot);
+ var newCopy = new Dictionary(snapshot);
newCopy.Remove(type);
typeMap = newCopy;
@@ -336,15 +336,20 @@ namespace Dapper
///
/// Get the DbType that maps to a given value.
///
+ /// The parameter to configure the value for.
/// The object to get a corresponding database type for.
[Obsolete(ObsoleteInternalUsageOnly, false)]
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
- public static DbType GetDbType(object value)
+ public static void SetDbType(IDataParameter parameter, object value)
{
- if (value == null || value is DBNull) return DbType.Object;
+ if (value == null || value is DBNull) return;
- return LookupDbType(value.GetType(), "n/a", false, out ITypeHandler _);
+ var dbType = LookupDbType(value.GetType(), "n/a", false, out ITypeHandler _);
+ if (DynamicParameters.ShouldSetDbType(dbType))
+ {
+ parameter.DbType = dbType.GetValueOrDefault();
+ }
}
///
@@ -357,7 +362,7 @@ namespace Dapper
[Obsolete(ObsoleteInternalUsageOnly, false)]
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
- public static DbType LookupDbType(Type type, string name, bool demand, out ITypeHandler handler)
+ public static DbType? LookupDbType(Type type, string name, bool demand, out ITypeHandler handler)
{
handler = null;
var nullUnderlyingType = Nullable.GetUnderlyingType(type);
@@ -366,7 +371,7 @@ namespace Dapper
{
type = Enum.GetUnderlyingType(type);
}
- if (typeMap.TryGetValue(type, out DbType dbType))
+ if (typeMap.TryGetValue(type, out var dbType))
{
return dbType;
}
@@ -2031,7 +2036,7 @@ namespace Dapper
var count = 0;
bool isString = value is IEnumerable;
bool isDbString = value is IEnumerable;
- DbType dbType = 0;
+ DbType? dbType = null;
int splitAt = SqlMapper.Settings.InListStringSplitCount;
bool viaSplit = splitAt >= 0
@@ -2076,9 +2081,9 @@ namespace Dapper
if (tmp != null && !(tmp is DBNull))
lastValue = tmp; // only interested in non-trivial values for padding
- if (listParam.DbType != dbType)
+ if (DynamicParameters.ShouldSetDbType(dbType) && listParam.DbType != dbType.GetValueOrDefault())
{
- listParam.DbType = dbType;
+ listParam.DbType = dbType.GetValueOrDefault();
}
command.Parameters.Add(listParam);
}
@@ -2092,7 +2097,10 @@ namespace Dapper
var padParam = command.CreateParameter();
padParam.ParameterName = namePrefix + count.ToString();
if (isString) padParam.Size = DbString.DefaultLength;
- padParam.DbType = dbType;
+ if (DynamicParameters.ShouldSetDbType(dbType))
+ {
+ padParam.DbType = dbType.GetValueOrDefault();
+ }
padParam.Value = lastValue;
command.Parameters.Add(padParam);
}
@@ -2528,7 +2536,7 @@ namespace Dapper
continue;
}
#pragma warning disable 618
- DbType dbType = LookupDbType(prop.PropertyType, prop.Name, true, out ITypeHandler handler);
+ DbType? dbType = LookupDbType(prop.PropertyType, prop.Name, true, out ITypeHandler handler);
#pragma warning restore 618
if (dbType == DynamicParameters.EnumerableMultiParameter)
{
@@ -2563,22 +2571,22 @@ namespace Dapper
il.Emit(OpCodes.Ldstr, prop.Name); // stack is now [parameters] [parameters] [parameter] [parameter] [name]
il.EmitCall(OpCodes.Callvirt, typeof(IDataParameter).GetProperty(nameof(IDataParameter.ParameterName)).GetSetMethod(), null);// stack is now [parameters] [parameters] [parameter]
}
- if (dbType != DbType.Time && handler == null) // https://connect.microsoft.com/VisualStudio/feedback/details/381934/sqlparameter-dbtype-dbtype-time-sets-the-parameter-to-sqldbtype-datetime-instead-of-sqldbtype-time
+ if (DynamicParameters.ShouldSetDbType(dbType) && dbType != DbType.Time && handler == null) // https://connect.microsoft.com/VisualStudio/feedback/details/381934/sqlparameter-dbtype-dbtype-time-sets-the-parameter-to-sqldbtype-datetime-instead-of-sqldbtype-time
{
il.Emit(OpCodes.Dup);// stack is now [parameters] [[parameters]] [parameter] [parameter]
- if (dbType == DbType.Object && prop.PropertyType == typeof(object)) // includes dynamic
+ if (dbType.GetValueOrDefault() == DbType.Object && prop.PropertyType == typeof(object)) // includes dynamic
{
// look it up from the param value
il.Emit(OpCodes.Ldloc, typedParameterLocal); // stack is now [parameters] [[parameters]] [parameter] [parameter] [typed-param]
il.Emit(callOpCode, prop.GetGetMethod()); // stack is [parameters] [[parameters]] [parameter] [parameter] [object-value]
- il.Emit(OpCodes.Call, typeof(SqlMapper).GetMethod(nameof(SqlMapper.GetDbType), BindingFlags.Static | BindingFlags.Public)); // stack is now [parameters] [[parameters]] [parameter] [parameter] [db-type]
+ il.Emit(OpCodes.Call, typeof(SqlMapper).GetMethod(nameof(SqlMapper.SetDbType), BindingFlags.Static | BindingFlags.Public)); // stack is now [parameters] [[parameters]] [parameter]
}
else
{
// constant value; nice and simple
- EmitInt32(il, (int)dbType);// stack is now [parameters] [[parameters]] [parameter] [parameter] [db-type]
+ EmitInt32(il, (int)dbType.GetValueOrDefault());// stack is now [parameters] [[parameters]] [parameter] [parameter] [db-type]
+ il.EmitCall(OpCodes.Callvirt, typeof(IDataParameter).GetProperty(nameof(IDataParameter.DbType)).GetSetMethod(), null);// stack is now [parameters] [[parameters]] [parameter]
}
- il.EmitCall(OpCodes.Callvirt, typeof(IDataParameter).GetProperty(nameof(IDataParameter.DbType)).GetSetMethod(), null);// stack is now [parameters] [[parameters]] [parameter]
}
il.Emit(OpCodes.Dup);// stack is now [parameters] [[parameters]] [parameter] [parameter]
diff --git a/nuget.config b/nuget.config
index b004e5cc..00f52b7e 100644
--- a/nuget.config
+++ b/nuget.config
@@ -2,6 +2,7 @@
+
\ No newline at end of file
diff --git a/tests/Dapper.Tests/Dapper.Tests.csproj b/tests/Dapper.Tests/Dapper.Tests.csproj
index f8402fca..15a6d39e 100644
--- a/tests/Dapper.Tests/Dapper.Tests.csproj
+++ b/tests/Dapper.Tests/Dapper.Tests.csproj
@@ -19,7 +19,7 @@
-
+
diff --git a/tests/Dapper.Tests/Providers/PostgresqlTests.cs b/tests/Dapper.Tests/Providers/PostgresqlTests.cs
index 0f1c4e45..1fc5cb33 100644
--- a/tests/Dapper.Tests/Providers/PostgresqlTests.cs
+++ b/tests/Dapper.Tests/Providers/PostgresqlTests.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
@@ -44,7 +45,7 @@ namespace Dapper.Tests
{
IDbTransaction transaction = conn.BeginTransaction();
conn.Execute("create table tcat ( id serial not null, breed character varying(20) not null, name character varying (20) not null);");
- conn.Execute("insert into tcat(breed, name) values(:breed, :name) ", Cats);
+ conn.Execute("insert into tcat(breed, name) values(:Breed, :Name) ", Cats);
var r = conn.Query("select * from tcat where id=any(:catids)", new { catids = new[] { 1, 3, 5 } });
Assert.Equal(3, r.Count());
@@ -55,6 +56,24 @@ namespace Dapper.Tests
}
}
+ [FactPostgresql]
+ public void TestPostgresqlListParameters()
+ {
+ using (var conn = GetOpenNpgsqlConnection())
+ {
+ IDbTransaction transaction = conn.BeginTransaction();
+ conn.Execute("create table tcat ( id serial not null, breed character varying(20) not null, name character varying (20) not null);");
+ conn.Execute("insert into tcat(breed, name) values(:Breed, :Name) ", new List(Cats));
+
+ var r = conn.Query("select * from tcat where id=any(:catids)", new { catids = new List { 1, 3, 5 } });
+ Assert.Equal(3, r.Count());
+ Assert.Equal(1, r.Count(c => c.Id == 1));
+ Assert.Equal(1, r.Count(c => c.Id == 3));
+ Assert.Equal(1, r.Count(c => c.Id == 5));
+ transaction.Rollback();
+ }
+ }
+
private class CharTable
{
public int Id { get; set; }
@@ -88,6 +107,15 @@ namespace Dapper.Tests
}
}
+ [FactPostgresql]
+ public void TestPostgresqlDateTimeUsage()
+ {
+ using (var conn = GetOpenNpgsqlConnection())
+ {
+ _ = conn.ExecuteScalar("SELECT @Now", new { Now = DateTime.UtcNow });
+ }
+ }
+
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class FactPostgresqlAttribute : FactAttribute
{