diff --git a/Dapper.StrongName/Dapper.StrongName.csproj b/Dapper.StrongName/Dapper.StrongName.csproj
index dee9414e2..36abdcb67 100644
--- a/Dapper.StrongName/Dapper.StrongName.csproj
+++ b/Dapper.StrongName/Dapper.StrongName.csproj
@@ -22,7 +22,7 @@
-
+
@@ -31,7 +31,8 @@
-
+
+
diff --git a/Dapper.Tests.Contrib/Dapper.Tests.Contrib.csproj b/Dapper.Tests.Contrib/Dapper.Tests.Contrib.csproj
index 45fb1a4e0..520dfb246 100644
--- a/Dapper.Tests.Contrib/Dapper.Tests.Contrib.csproj
+++ b/Dapper.Tests.Contrib/Dapper.Tests.Contrib.csproj
@@ -19,7 +19,7 @@
-
+
diff --git a/Dapper.Tests.Contrib/TestSuite.cs b/Dapper.Tests.Contrib/TestSuite.cs
index 0cd688e5e..c7a3cf9ad 100644
--- a/Dapper.Tests.Contrib/TestSuite.cs
+++ b/Dapper.Tests.Contrib/TestSuite.cs
@@ -5,10 +5,8 @@
using Dapper.Contrib.Extensions;
-#if !NETCOREAPP1_0
-using System.Transactions;
-#endif
#if !NETCOREAPP1_0 && !NETCOREAPP2_0
+using System.Transactions;
using System.Data.SqlServerCe;
#endif
using FactAttribute = Dapper.Tests.Contrib.SkippableFactAttribute;
@@ -527,7 +525,7 @@ public void Transactions()
}
}
-#if !NETCOREAPP1_0
+#if !NETCOREAPP1_0 && !NETCOREAPP2_0
[Fact]
public void TransactionScope()
{
diff --git a/Dapper.Tests/AsyncTests.cs b/Dapper.Tests/AsyncTests.cs
index 27fd24f8f..bfd57502d 100644
--- a/Dapper.Tests/AsyncTests.cs
+++ b/Dapper.Tests/AsyncTests.cs
@@ -353,28 +353,35 @@ public void RunSequentialVersusParallelSync()
Console.WriteLine("Pipeline: {0}ms", watch.ElapsedMilliseconds);
}
- [Fact]
- public void AssertNoCacheWorksForQueryMultiple()
+ [Collection("QueryCacheTests")]
+ public class AsyncQueryCacheTests : TestBase
{
- const int a = 123, b = 456;
- var cmdDef = new CommandDefinition(@"select @a; select @b;", new
- {
- a, b
- }, commandType: CommandType.Text, flags: CommandFlags.NoCache);
+ private SqlConnection _marsConnection;
+ private SqlConnection MarsConnection => _marsConnection ?? (_marsConnection = GetOpenConnection(true));
- int c, d;
- SqlMapper.PurgeQueryCache();
- int before = SqlMapper.GetCachedSQLCount();
- using (var multi = MarsConnection.QueryMultiple(cmdDef))
+ [Fact]
+ public void AssertNoCacheWorksForQueryMultiple()
{
- c = multi.Read().Single();
- d = multi.Read().Single();
+ const int a = 123, b = 456;
+ var cmdDef = new CommandDefinition(@"select @a; select @b;", new
+ {
+ a, b
+ }, commandType: CommandType.Text, flags: CommandFlags.NoCache);
+
+ int c, d;
+ SqlMapper.PurgeQueryCache();
+ int before = SqlMapper.GetCachedSQLCount();
+ using (var multi = MarsConnection.QueryMultiple(cmdDef))
+ {
+ c = multi.Read().Single();
+ d = multi.Read().Single();
+ }
+ int after = SqlMapper.GetCachedSQLCount();
+ before.IsEqualTo(0);
+ after.IsEqualTo(0);
+ c.IsEqualTo(123);
+ d.IsEqualTo(456);
}
- int after = SqlMapper.GetCachedSQLCount();
- before.IsEqualTo(0);
- after.IsEqualTo(0);
- c.IsEqualTo(123);
- d.IsEqualTo(456);
}
private class BasicType
diff --git a/Dapper.Tests/ConstructorTests.cs b/Dapper.Tests/ConstructorTests.cs
index 0613cbc7b..619286155 100644
--- a/Dapper.Tests/ConstructorTests.cs
+++ b/Dapper.Tests/ConstructorTests.cs
@@ -104,85 +104,6 @@ public bool GetWentThroughProperConstructor()
}
}
- [Fact]
- public void Issue461_TypeHandlerWorksInConstructor()
- {
- SqlMapper.AddTypeHandler(new Issue461_BlargHandler());
-
- connection.Execute(@"CREATE TABLE #Issue461 (
- Id int not null IDENTITY(1,1),
- SomeValue nvarchar(50),
- SomeBlargValue nvarchar(200),
- )");
- const string Expected = "abc123def";
- var blarg = new Blarg(Expected);
- connection.Execute(
- "INSERT INTO #Issue461 (SomeValue, SomeBlargValue) VALUES (@value, @blarg)",
- new { value = "what up?", blarg });
-
- // test: without constructor
- var parameterlessWorks = connection.QuerySingle("SELECT * FROM #Issue461");
- parameterlessWorks.Id.IsEqualTo(1);
- parameterlessWorks.SomeValue.IsEqualTo("what up?");
- parameterlessWorks.SomeBlargValue.Value.IsEqualTo(Expected);
-
- // test: via constructor
- var parameterDoesNot = connection.QuerySingle("SELECT * FROM #Issue461");
- parameterDoesNot.Id.IsEqualTo(1);
- parameterDoesNot.SomeValue.IsEqualTo("what up?");
- parameterDoesNot.SomeBlargValue.Value.IsEqualTo(Expected);
- }
-
- // 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
- private class Blarg
- {
- public Blarg(string value) { Value = value; }
- public string Value { get; }
- public override string ToString()
- {
- return Value;
- }
- }
-
- private class Issue461_BlargHandler : SqlMapper.TypeHandler
- {
- public override void SetValue(IDbDataParameter parameter, Blarg value)
- {
- parameter.Value = ((object)value.Value) ?? DBNull.Value;
- }
-
- public override Blarg Parse(object value)
- {
- string s = (value == null || value is DBNull) ? null : Convert.ToString(value);
- return new Blarg(s);
- }
- }
-
- private class Issue461_ParameterlessTypeConstructor
- {
- public int Id { get; set; }
-
- public string SomeValue { get; set; }
- public Blarg SomeBlargValue { get; set; }
- }
-
- private class Issue461_ParameterisedTypeConstructor
- {
- public Issue461_ParameterisedTypeConstructor(int id, string someValue, Blarg someBlargValue)
- {
- Id = id;
- SomeValue = someValue;
- SomeBlargValue = someBlargValue;
- }
-
- public int Id { get; }
-
- public string SomeValue { get; }
- public Blarg SomeBlargValue { get; }
- }
-
public static class AbstractInheritance
{
public abstract class Order
diff --git a/Dapper.Tests/Dapper.Tests.csproj b/Dapper.Tests/Dapper.Tests.csproj
index fc18b2b46..85d1fa3bc 100644
--- a/Dapper.Tests/Dapper.Tests.csproj
+++ b/Dapper.Tests/Dapper.Tests.csproj
@@ -23,7 +23,7 @@
-
+
diff --git a/Dapper.Tests/DataReaderTests.cs b/Dapper.Tests/DataReaderTests.cs
index 2a78f33c4..15415c51a 100644
--- a/Dapper.Tests/DataReaderTests.cs
+++ b/Dapper.Tests/DataReaderTests.cs
@@ -6,36 +6,40 @@ namespace Dapper.Tests
{
public partial class DataReaderTests : TestBase
{
- [Fact]
- public void GetSameReaderForSameShape()
+ [Collection("QueryCacheTests")]
+ public class DataReaderQueryCacheTests : TestBase
{
- var origReader = connection.ExecuteReader("select 'abc' as Name, 123 as Id");
- var origParser = origReader.GetRowParser(typeof(HazNameId));
+ [Fact]
+ public void GetSameReaderForSameShape()
+ {
+ var origReader = connection.ExecuteReader("select 'abc' as Name, 123 as Id");
+ var origParser = origReader.GetRowParser(typeof(HazNameId));
- var typedParser = origReader.GetRowParser();
+ var typedParser = origReader.GetRowParser();
- ReferenceEquals(origParser, typedParser).IsEqualTo(true);
+ ReferenceEquals(origParser, typedParser).IsEqualTo(true);
- var list = origReader.Parse().ToList();
- list.Count.IsEqualTo(1);
- list[0].Name.IsEqualTo("abc");
- list[0].Id.IsEqualTo(123);
- origReader.Dispose();
+ var list = origReader.Parse().ToList();
+ list.Count.IsEqualTo(1);
+ list[0].Name.IsEqualTo("abc");
+ list[0].Id.IsEqualTo(123);
+ origReader.Dispose();
- var secondReader = connection.ExecuteReader("select 'abc' as Name, 123 as Id");
- var secondParser = secondReader.GetRowParser(typeof(HazNameId));
- var thirdParser = secondReader.GetRowParser(typeof(HazNameId), 1);
+ var secondReader = connection.ExecuteReader("select 'abc' as Name, 123 as Id");
+ var secondParser = secondReader.GetRowParser(typeof(HazNameId));
+ var thirdParser = secondReader.GetRowParser(typeof(HazNameId), 1);
- list = secondReader.Parse().ToList();
- list.Count.IsEqualTo(1);
- list[0].Name.IsEqualTo("abc");
- list[0].Id.IsEqualTo(123);
- secondReader.Dispose();
+ list = secondReader.Parse().ToList();
+ list.Count.IsEqualTo(1);
+ list[0].Name.IsEqualTo("abc");
+ list[0].Id.IsEqualTo(123);
+ secondReader.Dispose();
- // now: should be different readers, but same parser
- ReferenceEquals(origReader, secondReader).IsEqualTo(false);
- ReferenceEquals(origParser, secondParser).IsEqualTo(true);
- ReferenceEquals(secondParser, thirdParser).IsEqualTo(false);
+ // now: should be different readers, but same parser
+ ReferenceEquals(origReader, secondReader).IsEqualTo(false);
+ ReferenceEquals(origParser, secondParser).IsEqualTo(true);
+ ReferenceEquals(secondParser, thirdParser).IsEqualTo(false);
+ }
}
[Fact]
diff --git a/Dapper.Tests/NullTests.cs b/Dapper.Tests/NullTests.cs
index 9199cba0d..20d52e091 100644
--- a/Dapper.Tests/NullTests.cs
+++ b/Dapper.Tests/NullTests.cs
@@ -2,6 +2,7 @@
using System.Linq;
namespace Dapper.Tests
{
+ [Collection("QueryCacheTests")]
public class NullTests : TestBase
{
[Fact]
diff --git a/Dapper.Tests/ParameterTests.cs b/Dapper.Tests/ParameterTests.cs
index dba446854..6f40f9111 100644
--- a/Dapper.Tests/ParameterTests.cs
+++ b/Dapper.Tests/ParameterTests.cs
@@ -38,6 +38,24 @@ void SqlMapper.IDynamicParameters.AddParameters(IDbCommand command, SqlMapper.Id
}
}
+ private static List CreateSqlDataRecordList(IEnumerable numbers)
+ {
+ var number_list = new List();
+
+ // Create an SqlMetaData object that describes our table type.
+ Microsoft.SqlServer.Server.SqlMetaData[] tvp_definition = { new Microsoft.SqlServer.Server.SqlMetaData("n", SqlDbType.Int) };
+
+ foreach (int n in numbers)
+ {
+ // Create a new record, using the metadata array above.
+ var rec = new Microsoft.SqlServer.Server.SqlDataRecord(tvp_definition);
+ rec.SetInt32(0, n); // Set the value.
+ number_list.Add(rec); // Add it to the list.
+ }
+
+ return number_list;
+ }
+
private class IntDynamicParam : SqlMapper.IDynamicParameters
{
private readonly IEnumerable numbers;
@@ -51,19 +69,8 @@ public void AddParameters(IDbCommand command, SqlMapper.Identity identity)
var sqlCommand = (SqlCommand)command;
sqlCommand.CommandType = CommandType.StoredProcedure;
- var number_list = new List();
-
- // Create an SqlMetaData object that describes our table type.
- Microsoft.SqlServer.Server.SqlMetaData[] tvp_definition = { new Microsoft.SqlServer.Server.SqlMetaData("n", SqlDbType.Int) };
-
- foreach (int n in numbers)
- {
- // Create a new record, using the metadata array above.
- var rec = new Microsoft.SqlServer.Server.SqlDataRecord(tvp_definition);
- rec.SetInt32(0, n); // Set the value.
- number_list.Add(rec); // Add it to the list.
- }
-
+ var number_list = CreateSqlDataRecordList(numbers);
+
// Add the table parameter.
var p = sqlCommand.Parameters.Add("ints", SqlDbType.Structured);
p.Direction = ParameterDirection.Input;
@@ -85,19 +92,8 @@ public void AddParameter(IDbCommand command, string name)
var sqlCommand = (SqlCommand)command;
sqlCommand.CommandType = CommandType.StoredProcedure;
- var number_list = new List();
-
- // Create an SqlMetaData object that describes our table type.
- Microsoft.SqlServer.Server.SqlMetaData[] tvp_definition = { new Microsoft.SqlServer.Server.SqlMetaData("n", SqlDbType.Int) };
-
- foreach (int n in numbers)
- {
- // Create a new record, using the metadata array above.
- var rec = new Microsoft.SqlServer.Server.SqlDataRecord(tvp_definition);
- rec.SetInt32(0, n); // Set the value.
- number_list.Add(rec); // Add it to the list.
- }
-
+ var number_list = CreateSqlDataRecordList(numbers);
+
// Add the table parameter.
var p = sqlCommand.Parameters.Add(name, SqlDbType.Structured);
p.Direction = ParameterDirection.Input;
@@ -218,7 +214,6 @@ public void TestMassiveStrings()
.IsEqualTo(str);
}
-#if !NETCOREAPP1_0
[Fact]
public void TestTVPWithAnonymousObject()
{
@@ -289,19 +284,8 @@ public DynamicParameterWithIntTVP(IEnumerable numbers)
var sqlCommand = (SqlCommand)command;
sqlCommand.CommandType = CommandType.StoredProcedure;
- var number_list = new List();
-
- // Create an SqlMetaData object that describes our table type.
- Microsoft.SqlServer.Server.SqlMetaData[] tvp_definition = { new Microsoft.SqlServer.Server.SqlMetaData("n", SqlDbType.Int) };
-
- foreach (int n in numbers)
- {
- // Create a new record, using the metadata array above.
- var rec = new Microsoft.SqlServer.Server.SqlDataRecord(tvp_definition);
- rec.SetInt32(0, n); // Set the value.
- number_list.Add(rec); // Add it to the list.
- }
-
+ var number_list = CreateSqlDataRecordList(numbers);
+
// Add the table parameter.
var p = sqlCommand.Parameters.Add("ints", SqlDbType.Structured);
p.Direction = ParameterDirection.Input;
@@ -344,6 +328,83 @@ public void TestTVPWithAdditionalParams()
}
}
+ [Fact]
+ public void TestSqlDataRecordListParametersWithAsTableValuedParameter()
+ {
+ try
+ {
+ connection.Execute("CREATE TYPE int_list_type AS TABLE (n int NOT NULL PRIMARY KEY)");
+ connection.Execute("CREATE PROC get_ints @integers int_list_type READONLY AS select * from @integers");
+
+ var records = CreateSqlDataRecordList(new int[] { 1, 2, 3 });
+
+ var nums = connection.Query("get_ints", new { integers = records.AsTableValuedParameter() }, commandType: CommandType.StoredProcedure).ToList();
+ nums.IsSequenceEqualTo(new int[] { 1, 2, 3 });
+
+ nums = connection.Query("select * from @integers", new { integers = records.AsTableValuedParameter("int_list_type") }).ToList();
+ nums.IsSequenceEqualTo(new int[] { 1, 2, 3 });
+
+ try
+ {
+ connection.Query("select * from @integers", new { integers = records.AsTableValuedParameter() }).First();
+ throw new InvalidOperationException();
+ }
+ catch (Exception ex)
+ {
+ ex.Message.Equals("The table type parameter 'ids' must have a valid type name.");
+ }
+ }
+ finally
+ {
+ try
+ {
+ connection.Execute("DROP PROC get_ints");
+ }
+ finally
+ {
+ connection.Execute("DROP TYPE int_list_type");
+ }
+ }
+ }
+
+ [Fact]
+ public void TestSqlDataRecordListParametersWithTypeHandlers()
+ {
+ try
+ {
+ connection.Execute("CREATE TYPE int_list_type AS TABLE (n int NOT NULL PRIMARY KEY)");
+ connection.Execute("CREATE PROC get_ints @integers int_list_type READONLY AS select * from @integers");
+
+ // Variable type has to be IEnumerable for TypeHandler to kick in.
+ IEnumerable records = CreateSqlDataRecordList(new int[] { 1, 2, 3 });
+
+ var nums = connection.Query("get_ints", new { integers = records }, commandType: CommandType.StoredProcedure).ToList();
+ nums.IsSequenceEqualTo(new int[] { 1, 2, 3 });
+
+ try
+ {
+ connection.Query("select * from @integers", new { integers = records }).First();
+ throw new InvalidOperationException();
+ }
+ catch (Exception ex)
+ {
+ ex.Message.Equals("The table type parameter 'ids' must have a valid type name.");
+ }
+ }
+ finally
+ {
+ try
+ {
+ connection.Execute("DROP PROC get_ints");
+ }
+ finally
+ {
+ connection.Execute("DROP TYPE int_list_type");
+ }
+ }
+ }
+
+#if !NETCOREAPP1_0
[Fact]
public void DataTableParameters()
{
diff --git a/Dapper.Tests/Providers/EntityFrameworkTests.cs b/Dapper.Tests/Providers/EntityFrameworkTests.cs
index 745f9148c..be9d54d63 100644
--- a/Dapper.Tests/Providers/EntityFrameworkTests.cs
+++ b/Dapper.Tests/Providers/EntityFrameworkTests.cs
@@ -4,6 +4,7 @@
namespace Dapper.Tests.Providers
{
+ [Collection("TypeHandlerTests")]
public class EntityFrameworkTests : TestBase
{
public EntityFrameworkTests()
diff --git a/Dapper.Tests/Providers/SqliteTests.cs b/Dapper.Tests/Providers/SqliteTests.cs
index b3d3e798d..25304f1cf 100644
--- a/Dapper.Tests/Providers/SqliteTests.cs
+++ b/Dapper.Tests/Providers/SqliteTests.cs
@@ -24,41 +24,45 @@ public void DapperEnumValue_Sqlite()
}
}
- [FactSqlite]
- public void Issue466_SqliteHatesOptimizations()
+ [Collection("TypeHandlerTests")]
+ public class SqliteTypeHandlerTests : TestBase
{
- using (var connection = GetSQLiteConnection())
+ [FactSqlite]
+ public void Issue466_SqliteHatesOptimizations()
{
- SqlMapper.ResetTypeHandlers();
- var row = connection.Query("select 42 as Id").First();
- row.Id.IsEqualTo(42);
- row = connection.Query("select 42 as Id").First();
- row.Id.IsEqualTo(42);
+ using (var connection = GetSQLiteConnection())
+ {
+ SqlMapper.ResetTypeHandlers();
+ var row = connection.Query("select 42 as Id").First();
+ row.Id.IsEqualTo(42);
+ row = connection.Query("select 42 as Id").First();
+ row.Id.IsEqualTo(42);
- SqlMapper.ResetTypeHandlers();
- row = connection.QueryFirst("select 42 as Id");
- row.Id.IsEqualTo(42);
- row = connection.QueryFirst("select 42 as Id");
- row.Id.IsEqualTo(42);
+ SqlMapper.ResetTypeHandlers();
+ row = connection.QueryFirst("select 42 as Id");
+ row.Id.IsEqualTo(42);
+ row = connection.QueryFirst("select 42 as Id");
+ row.Id.IsEqualTo(42);
+ }
}
- }
- [FactSqlite]
- public async Task Issue466_SqliteHatesOptimizations_Async()
- {
- using (var connection = GetSQLiteConnection())
+ [FactSqlite]
+ public async Task Issue466_SqliteHatesOptimizations_Async()
{
- SqlMapper.ResetTypeHandlers();
- var row = (await connection.QueryAsync("select 42 as Id").ConfigureAwait(false)).First();
- row.Id.IsEqualTo(42);
- row = (await connection.QueryAsync("select 42 as Id").ConfigureAwait(false)).First();
- row.Id.IsEqualTo(42);
+ using (var connection = GetSQLiteConnection())
+ {
+ SqlMapper.ResetTypeHandlers();
+ var row = (await connection.QueryAsync("select 42 as Id").ConfigureAwait(false)).First();
+ row.Id.IsEqualTo(42);
+ row = (await connection.QueryAsync("select 42 as Id").ConfigureAwait(false)).First();
+ row.Id.IsEqualTo(42);
- SqlMapper.ResetTypeHandlers();
- row = await connection.QueryFirstAsync("select 42 as Id").ConfigureAwait(false);
- row.Id.IsEqualTo(42);
- row = await connection.QueryFirstAsync("select 42 as Id").ConfigureAwait(false);
- row.Id.IsEqualTo(42);
+ SqlMapper.ResetTypeHandlers();
+ row = await connection.QueryFirstAsync("select 42 as Id").ConfigureAwait(false);
+ row.Id.IsEqualTo(42);
+ row = await connection.QueryFirstAsync("select 42 as Id").ConfigureAwait(false);
+ row.Id.IsEqualTo(42);
+ }
}
}
diff --git a/Dapper.Tests/TypeHandlerTests.cs b/Dapper.Tests/TypeHandlerTests.cs
index 722f1e887..0ea50a7e7 100644
--- a/Dapper.Tests/TypeHandlerTests.cs
+++ b/Dapper.Tests/TypeHandlerTests.cs
@@ -8,46 +8,96 @@
namespace Dapper.Tests
{
+ [Collection("TypeHandlerTests")]
public class TypeHandlerTests : TestBase
{
- [Fact]
- public void TestChangingDefaultStringTypeMappingToAnsiString()
+ [Collection("QueryCacheTests")]
+ public class TypeHandlerQueryCacheTests : TestBase
{
- const string sql = "SELECT SQL_VARIANT_PROPERTY(CONVERT(sql_variant, @testParam),'BaseType') AS BaseType";
- var param = new { testParam = "TestString" };
+ [Fact]
+ public void TestChangingDefaultStringTypeMappingToAnsiString()
+ {
+ const string sql = "SELECT SQL_VARIANT_PROPERTY(CONVERT(sql_variant, @testParam),'BaseType') AS BaseType";
+ var param = new { testParam = "TestString" };
- var result01 = connection.Query(sql, param).FirstOrDefault();
- result01.IsEqualTo("nvarchar");
+ var result01 = connection.Query(sql, param).FirstOrDefault();
+ result01.IsEqualTo("nvarchar");
- SqlMapper.PurgeQueryCache();
+ SqlMapper.PurgeQueryCache();
- SqlMapper.AddTypeMap(typeof(string), DbType.AnsiString); // Change Default String Handling to AnsiString
- var result02 = connection.Query(sql, param).FirstOrDefault();
- result02.IsEqualTo("varchar");
+ SqlMapper.AddTypeMap(typeof(string), DbType.AnsiString); // Change Default String Handling to AnsiString
+ var result02 = connection.Query(sql, param).FirstOrDefault();
+ result02.IsEqualTo("varchar");
- SqlMapper.PurgeQueryCache();
- SqlMapper.AddTypeMap(typeof(string), DbType.String); // Restore Default to Unicode String
- }
+ SqlMapper.PurgeQueryCache();
+ SqlMapper.AddTypeMap(typeof(string), DbType.String); // Restore Default to Unicode String
+ }
- [Fact]
- public void TestChangingDefaultStringTypeMappingToAnsiStringFirstOrDefault()
- {
- const string sql = "SELECT SQL_VARIANT_PROPERTY(CONVERT(sql_variant, @testParam),'BaseType') AS BaseType";
- var param = new { testParam = "TestString" };
+ [Fact]
+ public void TestChangingDefaultStringTypeMappingToAnsiStringFirstOrDefault()
+ {
+ const string sql = "SELECT SQL_VARIANT_PROPERTY(CONVERT(sql_variant, @testParam),'BaseType') AS BaseType";
+ var param = new { testParam = "TestString" };
- var result01 = connection.QueryFirstOrDefault(sql, param);
- result01.IsEqualTo("nvarchar");
+ var result01 = connection.QueryFirstOrDefault(sql, param);
+ result01.IsEqualTo("nvarchar");
- SqlMapper.PurgeQueryCache();
+ SqlMapper.PurgeQueryCache();
- SqlMapper.AddTypeMap(typeof(string), DbType.AnsiString); // Change Default String Handling to AnsiString
- var result02 = connection.QueryFirstOrDefault(sql, param);
- result02.IsEqualTo("varchar");
+ SqlMapper.AddTypeMap(typeof(string), DbType.AnsiString); // Change Default String Handling to AnsiString
+ var result02 = connection.QueryFirstOrDefault(sql, param);
+ result02.IsEqualTo("varchar");
- SqlMapper.PurgeQueryCache();
- SqlMapper.AddTypeMap(typeof(string), DbType.String); // Restore Default to Unicode String
- }
+ SqlMapper.PurgeQueryCache();
+ SqlMapper.AddTypeMap(typeof(string), DbType.String); // Restore Default to Unicode String
+ }
+
+ [Fact]
+ public void TestCustomTypeMap()
+ {
+ // default mapping
+ var item = connection.Query("Select 'AVal' as A, 'BVal' as B").Single();
+ item.A.IsEqualTo("AVal");
+ item.B.IsEqualTo("BVal");
+
+ // custom mapping
+ var map = new CustomPropertyTypeMap(typeof(TypeWithMapping),
+ (type, columnName) => type.GetProperties().FirstOrDefault(prop => GetDescriptionFromAttribute(prop) == columnName));
+ SqlMapper.SetTypeMap(typeof(TypeWithMapping), map);
+
+ item = connection.Query("Select 'AVal' as A, 'BVal' as B").Single();
+ item.A.IsEqualTo("BVal");
+ item.B.IsEqualTo("AVal");
+
+ // reset to default
+ SqlMapper.SetTypeMap(typeof(TypeWithMapping), null);
+ item = connection.Query("Select 'AVal' as A, 'BVal' as B").Single();
+ item.A.IsEqualTo("AVal");
+ item.B.IsEqualTo("BVal");
+ }
+
+ private static string GetDescriptionFromAttribute(MemberInfo member)
+ {
+ if (member == null) return null;
+#if NETCOREAPP1_0
+ var data = member.CustomAttributes.FirstOrDefault(x => x.AttributeType == typeof(DescriptionAttribute));
+ return (string)data?.ConstructorArguments.Single().Value;
+#else
+ var attrib = (DescriptionAttribute)Attribute.GetCustomAttribute(member, typeof(DescriptionAttribute), false);
+ return attrib?.Description;
+#endif
+ }
+
+ public class TypeWithMapping
+ {
+ [Description("B")]
+ public string A { get; set; }
+ [Description("A")]
+ public string B { get; set; }
+ }
+ }
+
[Fact]
public void Issue136_ValueTypeHandlers()
{
@@ -518,51 +568,6 @@ private class ResultsChangeType
public int Z { get; set; }
}
- [Fact]
- public void TestCustomTypeMap()
- {
- // default mapping
- var item = connection.Query("Select 'AVal' as A, 'BVal' as B").Single();
- item.A.IsEqualTo("AVal");
- item.B.IsEqualTo("BVal");
-
- // custom mapping
- var map = new CustomPropertyTypeMap(typeof(TypeWithMapping),
- (type, columnName) => type.GetProperties().FirstOrDefault(prop => GetDescriptionFromAttribute(prop) == columnName));
- SqlMapper.SetTypeMap(typeof(TypeWithMapping), map);
-
- item = connection.Query("Select 'AVal' as A, 'BVal' as B").Single();
- item.A.IsEqualTo("BVal");
- item.B.IsEqualTo("AVal");
-
- // reset to default
- SqlMapper.SetTypeMap(typeof(TypeWithMapping), null);
- item = connection.Query("Select 'AVal' as A, 'BVal' as B").Single();
- item.A.IsEqualTo("AVal");
- item.B.IsEqualTo("BVal");
- }
-
- private static string GetDescriptionFromAttribute(MemberInfo member)
- {
- if (member == null) return null;
-#if NETCOREAPP1_0
- var data = member.CustomAttributes.FirstOrDefault(x => x.AttributeType == typeof(DescriptionAttribute));
- return (string)data?.ConstructorArguments.Single().Value;
-#else
- var attrib = (DescriptionAttribute)Attribute.GetCustomAttribute(member, typeof(DescriptionAttribute), false);
- return attrib?.Description;
-#endif
- }
-
- public class TypeWithMapping
- {
- [Description("B")]
- public string A { get; set; }
-
- [Description("A")]
- public string B { get; set; }
- }
-
public class WrongTypes
{
public int A { get; set; }
@@ -658,5 +663,84 @@ public void SO29343103_UtcDates()
var delta = returned - date;
Assert.IsTrue(delta.TotalMilliseconds >= -10 && delta.TotalMilliseconds <= 10);
}
+
+ [Fact]
+ public void Issue461_TypeHandlerWorksInConstructor()
+ {
+ SqlMapper.AddTypeHandler(new Issue461_BlargHandler());
+
+ connection.Execute(@"CREATE TABLE #Issue461 (
+ Id int not null IDENTITY(1,1),
+ SomeValue nvarchar(50),
+ SomeBlargValue nvarchar(200),
+ )");
+ const string Expected = "abc123def";
+ var blarg = new Blarg(Expected);
+ connection.Execute(
+ "INSERT INTO #Issue461 (SomeValue, SomeBlargValue) VALUES (@value, @blarg)",
+ new { value = "what up?", blarg });
+
+ // test: without constructor
+ var parameterlessWorks = connection.QuerySingle("SELECT * FROM #Issue461");
+ parameterlessWorks.Id.IsEqualTo(1);
+ parameterlessWorks.SomeValue.IsEqualTo("what up?");
+ parameterlessWorks.SomeBlargValue.Value.IsEqualTo(Expected);
+
+ // test: via constructor
+ var parameterDoesNot = connection.QuerySingle("SELECT * FROM #Issue461");
+ parameterDoesNot.Id.IsEqualTo(1);
+ parameterDoesNot.SomeValue.IsEqualTo("what up?");
+ parameterDoesNot.SomeBlargValue.Value.IsEqualTo(Expected);
+ }
+
+ // 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
+ private class Blarg
+ {
+ public Blarg(string value) { Value = value; }
+ public string Value { get; }
+ public override string ToString()
+ {
+ return Value;
+ }
+ }
+
+ private class Issue461_BlargHandler : SqlMapper.TypeHandler
+ {
+ public override void SetValue(IDbDataParameter parameter, Blarg value)
+ {
+ parameter.Value = ((object)value.Value) ?? DBNull.Value;
+ }
+
+ public override Blarg Parse(object value)
+ {
+ string s = (value == null || value is DBNull) ? null : Convert.ToString(value);
+ return new Blarg(s);
+ }
+ }
+
+ private class Issue461_ParameterlessTypeConstructor
+ {
+ public int Id { get; set; }
+
+ public string SomeValue { get; set; }
+ public Blarg SomeBlargValue { get; set; }
+ }
+
+ private class Issue461_ParameterisedTypeConstructor
+ {
+ public Issue461_ParameterisedTypeConstructor(int id, string someValue, Blarg someBlargValue)
+ {
+ Id = id;
+ SomeValue = someValue;
+ SomeBlargValue = someBlargValue;
+ }
+
+ public int Id { get; }
+
+ public string SomeValue { get; }
+ public Blarg SomeBlargValue { get; }
+ }
}
}
diff --git a/Dapper/Dapper.csproj b/Dapper/Dapper.csproj
index 75459323d..e4007559b 100644
--- a/Dapper/Dapper.csproj
+++ b/Dapper/Dapper.csproj
@@ -17,7 +17,7 @@
-
+
@@ -26,7 +26,8 @@
-
+
+
diff --git a/Dapper/SqlDataRecordHandler.cs b/Dapper/SqlDataRecordHandler.cs
index 358048039..301aa36ab 100644
--- a/Dapper/SqlDataRecordHandler.cs
+++ b/Dapper/SqlDataRecordHandler.cs
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Data;
-#if !NETSTANDARD1_3
namespace Dapper
{
internal sealed class SqlDataRecordHandler : SqlMapper.ITypeHandler
@@ -18,4 +17,3 @@ public void SetValue(IDbDataParameter parameter, object value)
}
}
}
-#endif
\ No newline at end of file
diff --git a/Dapper/SqlDataRecordListTVPParameter.cs b/Dapper/SqlDataRecordListTVPParameter.cs
index ccae089ed..8e8384705 100644
--- a/Dapper/SqlDataRecordListTVPParameter.cs
+++ b/Dapper/SqlDataRecordListTVPParameter.cs
@@ -1,8 +1,7 @@
using System;
using System.Collections.Generic;
using System.Data;
-using System.Reflection;
-#if !NETSTANDARD1_3
+
namespace Dapper
{
///
@@ -23,18 +22,6 @@ public SqlDataRecordListTVPParameter(IEnumerable setTypeName;
-
- static SqlDataRecordListTVPParameter()
- {
- var prop = typeof(System.Data.SqlClient.SqlParameter).GetProperty(nameof(System.Data.SqlClient.SqlParameter.TypeName), BindingFlags.Instance | BindingFlags.Public);
- if (prop != null && prop.PropertyType == typeof(string) && prop.CanWrite)
- {
- setTypeName = (Action)
- Delegate.CreateDelegate(typeof(Action), prop.GetSetMethod());
- }
- }
-
void SqlMapper.ICustomQueryParameter.AddParameter(IDbCommand command, string name)
{
var param = command.CreateParameter();
@@ -54,4 +41,3 @@ internal static void Set(IDbDataParameter parameter, IEnumerable();
#if !NETSTANDARD1_3
AddTypeHandlerImpl(typeof(DataTable), new DataTableHandler(), clone);
+#endif
try
{
AddSqlDataRecordsTypeHandler(clone);
}
catch { /* https://github.com/StackExchange/dapper-dot-net/issues/424 */ }
-#endif
AddTypeHandlerImpl(typeof(XmlDocument), new XmlDocumentHandler(), clone);
AddTypeHandlerImpl(typeof(XDocument), new XDocumentHandler(), clone);
AddTypeHandlerImpl(typeof(XElement), new XElementHandler(), clone);
}
-#if !NETSTANDARD1_3
[MethodImpl(MethodImplOptions.NoInlining)]
private static void AddSqlDataRecordsTypeHandler(bool clone)
{
AddTypeHandlerImpl(typeof(IEnumerable), new SqlDataRecordHandler(), clone);
}
-#endif
///
/// Configure the specified type to be mapped to a given db-type.
@@ -3662,15 +3660,15 @@ public static void SetTypeName(this DataTable table, string typeName)
/// The that has a type name associated with it.
public static string GetTypeName(this DataTable table) =>
table?.ExtendedProperties[DataTableTypeNameKey] as string;
+#endif
///
- /// Used to pass a IEnumerable<SqlDataRecord> as a .
+ /// Used to pass a IEnumerable<SqlDataRecord> as a TableValuedParameter.
///
- /// Thhe list of records to convert to TVPs.
+ /// The list of records to convert to TVPs.
/// The sql parameter type name.
public static ICustomQueryParameter AsTableValuedParameter(this IEnumerable list, string typeName = null) =>
new SqlDataRecordListTVPParameter(list, typeName);
-#endif
// one per thread
[ThreadStatic]