Skip to content Sign up Sign in This repository Explore Features Enterprise Blog Watch 390 Star 2,538 Fork 844 StackExchange/dapper-dot-net branch: master dapper-dot-net/Tests/Tests.cs @mgravellmgravell 5 days ago SO30435185; make it clearer if the caller is passing an array (etc) w… 21 contributors @mgravell @invalid-email-address @vosen @SamSaffron @jamesholwell @azhmur @jkonecki @brannon @teamyudin @markjerz @simonkang @kevin-montrose @johnleegrant @mrange @tms @fbdegroot @tuespetre @greygeek @RichCzyzewski @matwilko @xps RawBlameHistory 4615 lines (4028 sloc) 178.799 kb //#define POSTGRESQL // uncomment to run postgres tests #if DNXCORE50 using IDbCommand = global::System.Data.Common.DbCommand; using IDbDataParameter = global::System.Data.Common.DbParameter; using IDbConnection = global::System.Data.Common.DbConnection; using IDbTransaction = global::System.Data.Common.DbTransaction; using IDataReader = global::System.Data.Common.DbDataReader; #endif using System; using System.Collections.Generic; using System.Data.SqlClient; using System.Linq; using Dapper; using System.IO; using System.Data; using System.Collections; using System.Reflection; using System.Dynamic; using System.ComponentModel; using Microsoft.CSharp.RuntimeBinder; using System.Data.Common; using System.Globalization; using System.Threading; using System.Data.SqlTypes; using System.Diagnostics; #if EXTERNALS using FirebirdSql.Data.FirebirdClient; using System.Data.Entity.Spatial; using Microsoft.SqlServer.Types; using System.Data.SqlServerCe; #if POSTGRESQL using Npgsql; #endif #endif #if DNXCORE50 namespace System.ComponentModel { public sealed class DescriptionAttribute : Attribute { public DescriptionAttribute(string description) { Description = description; } public string Description {get;private set;} } } namespace System { public enum GenericUriParserOptions { Default } public class GenericUriParser { private GenericUriParserOptions options; public GenericUriParser(GenericUriParserOptions options) { this.options = options; } } } #endif namespace SqlMapper { class Tests { SqlConnection connection = Program.GetOpenConnection(); public class AbstractInheritance { public abstract class Order { internal int Internal { get; set; } protected int Protected { get; set; } public int Public { get; set; } public int ProtectedVal { get { return Protected; } } } public class ConcreteOrder : Order { public int Concrete { get; set; } } } class UserWithConstructor { public UserWithConstructor(int id, string name) { Ident = id; FullName = name; } public int Ident { get; set; } public string FullName { get; set; } } class PostWithConstructor { public PostWithConstructor(int id, int ownerid, string content) { Ident = id; FullContent = content; } public int Ident { get; set; } public UserWithConstructor Owner { get; set; } public string FullContent { get; set; } public Comment Comment { get; set; } } public void TestMultiMapWithConstructor() { var createSql = @" create table #Users (Id int, Name varchar(20)) create table #Posts (Id int, OwnerId int, Content varchar(20)) insert #Users values(99, 'Sam') insert #Users values(2, 'I am') insert #Posts values(1, 99, 'Sams Post1') insert #Posts values(2, 99, 'Sams Post2') insert #Posts values(3, null, 'no ones post')"; connection.Execute(createSql); try { string sql = @"select * from #Posts p left join #Users u on u.Id = p.OwnerId Order by p.Id"; PostWithConstructor[] data = connection.Query<PostWithConstructor, UserWithConstructor, PostWithConstructor>(sql, (post, user) => { post.Owner = user; return post; }).ToArray(); var p = data.First(); p.FullContent.IsEqualTo("Sams Post1"); p.Ident.IsEqualTo(1); p.Owner.FullName.IsEqualTo("Sam"); p.Owner.Ident.IsEqualTo(99); data[2].Owner.IsNull(); } finally { connection.Execute("drop table #Users drop table #Posts"); } } class MultipleConstructors { public MultipleConstructors() { } public MultipleConstructors(int a, string b) { A = a + 1; B = b + "!"; } public int A { get; set; } public string B { get; set; } } public void TestMultipleConstructors() { MultipleConstructors mult = connection.Query<MultipleConstructors>("select 0 A, 'Dapper' b").First(); mult.A.IsEqualTo(0); mult.B.IsEqualTo("Dapper"); } class ConstructorsWithAccessModifiers { private ConstructorsWithAccessModifiers() { } public ConstructorsWithAccessModifiers(int a, string b) { A = a + 1; B = b + "!"; } public int A { get; set; } public string B { get; set; } } public void TestConstructorsWithAccessModifiers() { ConstructorsWithAccessModifiers value = connection.Query<ConstructorsWithAccessModifiers>("select 0 A, 'Dapper' b").First(); value.A.IsEqualTo(1); value.B.IsEqualTo("Dapper!"); } class NoDefaultConstructor { public NoDefaultConstructor(int a1, int? b1, float f1, string s1, Guid G1) { A = a1; B = b1; F = f1; S = s1; G = G1; } public int A { get; set; } public int? B { get; set; } public float F { get; set; } public string S { get; set; } public Guid G { get; set; } } public void TestNoDefaultConstructor() { var guid = Guid.NewGuid(); NoDefaultConstructor nodef = connection.Query<NoDefaultConstructor>("select CAST(NULL AS integer) A1, CAST(NULL AS integer) b1, CAST(NULL AS real) f1, 'Dapper' s1, G1 = @id", new { id = guid }).First(); nodef.A.IsEqualTo(0); nodef.B.IsEqualTo(null); nodef.F.IsEqualTo(0); nodef.S.IsEqualTo("Dapper"); nodef.G.IsEqualTo(guid); } class NoDefaultConstructorWithChar { public NoDefaultConstructorWithChar(char c1, char? c2, char? c3) { Char1 = c1; Char2 = c2; Char3 = c3; } public char Char1 { get; set; } public char? Char2 { get; set; } public char? Char3 { get; set; } } public void TestNoDefaultConstructorWithChar() { const char c1 = 'ą'; const char c3 = 'ó'; NoDefaultConstructorWithChar nodef = connection.Query<NoDefaultConstructorWithChar>("select @c1 c1, @c2 c2, @c3 c3", new { c1 = c1, c2 = (char?)null, c3 = c3 }).First(); nodef.Char1.IsEqualTo(c1); nodef.Char2.IsEqualTo(null); nodef.Char3.IsEqualTo(c3); } class NoDefaultConstructorWithEnum { public NoDefaultConstructorWithEnum(ShortEnum e1, ShortEnum? n1, ShortEnum? n2) { E = e1; NE1 = n1; NE2 = n2; } public ShortEnum E { get; set; } public ShortEnum? NE1 { get; set; } public ShortEnum? NE2 { get; set; } } public void TestNoDefaultConstructorWithEnum() { NoDefaultConstructorWithEnum nodef = connection.Query<NoDefaultConstructorWithEnum>("select cast(2 as smallint) E1, cast(5 as smallint) n1, cast(null as smallint) n2").First(); nodef.E.IsEqualTo(ShortEnum.Two); nodef.NE1.IsEqualTo(ShortEnum.Five); nodef.NE2.IsEqualTo(null); } #if EXTERNALS class NoDefaultConstructorWithBinary { public System.Data.Linq.Binary Value { get; set; } public int Ynt { get; set; } public NoDefaultConstructorWithBinary(System.Data.Linq.Binary val) { Value = val; } } public void TestNoDefaultConstructorBinary() { byte[] orig = new byte[20]; new Random(123456).NextBytes(orig); var input = new System.Data.Linq.Binary(orig); var output = connection.Query<NoDefaultConstructorWithBinary>("select @input as val", new { input }).First().Value; output.ToArray().IsSequenceEqualTo(orig); } #endif // http://stackoverflow.com/q/8593871 public void TestAbstractInheritance() { var order = connection.Query<AbstractInheritance.ConcreteOrder>("select 1 Internal,2 Protected,3 [Public],4 Concrete").First(); order.Internal.IsEqualTo(1); order.ProtectedVal.IsEqualTo(2); order.Public.IsEqualTo(3); order.Concrete.IsEqualTo(4); } public void TestListOfAnsiStrings() { var results = connection.Query<string>("select * from (select 'a' str union select 'b' union select 'c') X where str in @strings", new { strings = new[] { new DbString { IsAnsi = true, Value = "a" }, new DbString { IsAnsi = true, Value = "b" } } }).ToList(); results[0].IsEqualTo("a"); results[1].IsEqualTo("b"); } public void TestNullableGuidSupport() { var guid = connection.Query<Guid?>("select null").First(); guid.IsNull(); guid = Guid.NewGuid(); var guid2 = connection.Query<Guid?>("select @guid", new { guid }).First(); guid.IsEqualTo(guid2); } public void TestNonNullableGuidSupport() { var guid = Guid.NewGuid(); var guid2 = connection.Query<Guid?>("select @guid", new { guid }).First(); Assert.IsTrue(guid == guid2); } struct Car { public enum TrapEnum : int { A = 1, B = 2 } #pragma warning disable 0649 public string Name; #pragma warning restore 0649 public int Age { get; set; } public TrapEnum Trap { get; set; } } struct CarWithAllProps { public string Name { get; set; } public int Age { get; set; } public Car.TrapEnum Trap { get; set; } } public void TestStructs() { var car = connection.Query<Car>("select 'Ford' Name, 21 Age, 2 Trap").First(); car.Age.IsEqualTo(21); car.Name.IsEqualTo("Ford"); ((int)car.Trap).IsEqualTo(2); } public void TestStructAsParam() { var car1 = new CarWithAllProps { Name = "Ford", Age = 21, Trap = Car.TrapEnum.B }; // note Car has Name as a field; parameters only respect properties at the moment var car2 = connection.Query<CarWithAllProps>("select @Name Name, @Age Age, @Trap Trap", car1).First(); car2.Name.IsEqualTo(car1.Name); car2.Age.IsEqualTo(car1.Age); car2.Trap.IsEqualTo(car1.Trap); } public void SelectListInt() { connection.Query<int>("select 1 union all select 2 union all select 3") .IsSequenceEqualTo(new[] { 1, 2, 3 }); } public void SelectBinary() { connection.Query<byte[]>("select cast(1 as varbinary(4))").First().SequenceEqual(new byte[] { 1 }); } public void PassInIntArray() { connection.Query<int>("select * from (select 1 as Id union all select 2 union all select 3) as X where Id in @Ids", new { Ids = new int[] { 1, 2, 3 }.AsEnumerable() }) .IsSequenceEqualTo(new[] { 1, 2, 3 }); } public void PassInEmptyIntArray() { connection.Query<int>("select * from (select 1 as Id union all select 2 union all select 3) as X where Id in @Ids", new { Ids = new int[0] }) .IsSequenceEqualTo(new int[0]); } public void TestSchemaChanged() { connection.Execute("create table #dog(Age int, Name nvarchar(max)) insert #dog values(1, 'Alf')"); try { var d = connection.Query<Dog>("select * from #dog").Single(); d.Name.IsEqualTo("Alf"); d.Age.IsEqualTo(1); connection.Execute("alter table #dog drop column Name"); d = connection.Query<Dog>("select * from #dog").Single(); d.Name.IsNull(); d.Age.IsEqualTo(1); } finally { connection.Execute("drop table #dog"); } } public void TestSchemaChangedMultiMap() { connection.Execute("create table #dog(Age int, Name nvarchar(max)) insert #dog values(1, 'Alf')"); try { var tuple = connection.Query<Dog, Dog, Tuple<Dog, Dog>>("select * from #dog d1 join #dog d2 on 1=1", (d1, d2) => Tuple.Create(d1, d2), splitOn: "Age").Single(); tuple.Item1.Name.IsEqualTo("Alf"); tuple.Item1.Age.IsEqualTo(1); tuple.Item2.Name.IsEqualTo("Alf"); tuple.Item2.Age.IsEqualTo(1); connection.Execute("alter table #dog drop column Name"); tuple = connection.Query<Dog, Dog, Tuple<Dog, Dog>>("select * from #dog d1 join #dog d2 on 1=1", (d1, d2) => Tuple.Create(d1, d2), splitOn: "Age").Single(); tuple.Item1.Name.IsNull(); tuple.Item1.Age.IsEqualTo(1); tuple.Item2.Name.IsNull(); tuple.Item2.Age.IsEqualTo(1); } finally { connection.Execute("drop table #dog"); } } public void TestReadMultipleIntegersWithSplitOnAny() { connection.Query<int, int, int, Tuple<int, int, int>>( "select 1,2,3 union all select 4,5,6", Tuple.Create, splitOn: "*") .IsSequenceEqualTo(new[] { Tuple.Create(1, 2, 3), Tuple.Create(4, 5, 6) }); } public void TestDoubleParam() { connection.Query<double>("select @d", new { d = 0.1d }).First() .IsEqualTo(0.1d); } public void TestBoolParam() { connection.Query<bool>("select @b", new { b = false }).First() .IsFalse(); } // http://code.google.com/p/dapper-dot-net/issues/detail?id=70 // https://connect.microsoft.com/VisualStudio/feedback/details/381934/sqlparameter-dbtype-dbtype-time-sets-the-parameter-to-sqldbtype-datetime-instead-of-sqldbtype-time public void TestTimeSpanParam() { connection.Query<TimeSpan>("select @ts", new { ts = TimeSpan.FromMinutes(42) }).First() .IsEqualTo(TimeSpan.FromMinutes(42)); } public void TestStrings() { connection.Query<string>(@"select 'a' a union select 'b'") .IsSequenceEqualTo(new[] { "a", "b" }); } // see http://stackoverflow.com/questions/16726709/string-format-with-sql-wildcard-causing-dapper-query-to-break public void CheckComplexConcat() { string end_wildcard = @" SELECT * FROM #users16726709 WHERE (first_name LIKE CONCAT(@search_term, '%') OR last_name LIKE CONCAT(@search_term, '%'));"; string both_wildcards = @" SELECT * FROM #users16726709 WHERE (first_name LIKE CONCAT('%', @search_term, '%') OR last_name LIKE CONCAT('%', @search_term, '%'));"; string formatted = @" SELECT * FROM #users16726709 WHERE (first_name LIKE {0} OR last_name LIKE {0});"; string use_end_only = @"CONCAT(@search_term, '%')"; string use_both = @"CONCAT('%', @search_term, '%')"; // if true, slower query due to not being able to use indices, but will allow searching inside strings bool allow_start_wildcards = false; string query = String.Format(formatted, allow_start_wildcards ? use_both : use_end_only); string term = "F"; // the term the user searched for connection.Execute(@"create table #users16726709 (first_name varchar(200), last_name varchar(200)) insert #users16726709 values ('Fred','Bloggs') insert #users16726709 values ('Tony','Farcus') insert #users16726709 values ('Albert','TenoF')"); // Using Dapper connection.Query(end_wildcard, new { search_term = term }).Count().IsEqualTo(2); connection.Query(both_wildcards, new { search_term = term }).Count().IsEqualTo(3); connection.Query(query, new { search_term = term }).Count().IsEqualTo(2); } enum EnumParam : short { None, A, B } class EnumParamObject { public EnumParam A { get; set; } public EnumParam? B { get; set; } public EnumParam? C { get; set; } } class EnumParamObjectNonNullable { public EnumParam A { get; set; } public EnumParam? B { get; set; } public EnumParam? C { get; set; } } public void TestEnumParamsWithNullable() { EnumParam a = EnumParam.A; EnumParam? b = EnumParam.B, c = null; var obj = connection.Query<EnumParamObject>("select @a as A, @b as B, @c as C", new { a, b, c }).Single(); obj.A.IsEqualTo(EnumParam.A); obj.B.IsEqualTo(EnumParam.B); obj.C.IsEqualTo(null); } public void TestEnumParamsWithoutNullable() { EnumParam a = EnumParam.A; EnumParam b = EnumParam.B, c = 0; var obj = connection.Query<EnumParamObjectNonNullable>("select @a as A, @b as B, @c as C", new { a, b, c }).Single(); obj.A.IsEqualTo(EnumParam.A); obj.B.IsEqualTo(EnumParam.B); obj.C.IsEqualTo((EnumParam)0); } public class Dog { public int? Age { get; set; } public Guid Id { get; set; } public string Name { get; set; } public float? Weight { get; set; } public int IgnoredProperty { get { return 1; } } } public void TestExtraFields() { var guid = Guid.NewGuid(); var dog = connection.Query<Dog>("select '' as Extra, 1 as Age, 0.1 as Name1 , Id = @id", new { id = guid }); dog.Count() .IsEqualTo(1); dog.First().Age .IsEqualTo(1); dog.First().Id .IsEqualTo(guid); } #if EXTERNALS // see http://stackoverflow.com/q/18847510/23354 public void TestOleDbParameters() { using (var conn = ConnectViaOledb()) { var row = conn.Query("select Id = ?, Age = ?", new { foo = 12, bar = 23 } // these names DO NOT MATTER!!! ).Single(); int age = row.Age; int id = row.Id; age.IsEqualTo(23); id.IsEqualTo(12); } } System.Data.OleDb.OleDbConnection ConnectViaOledb() { var conn = new System.Data.OleDb.OleDbConnection(Program.OleDbConnectionString); conn.Open(); return conn; } #endif public void TestStrongType() { var guid = Guid.NewGuid(); var dog = connection.Query<Dog>("select Age = @Age, Id = @Id", new { Age = (int?)null, Id = guid }); dog.Count() .IsEqualTo(1); dog.First().Age .IsNull(); dog.First().Id .IsEqualTo(guid); } public void TestSimpleNull() { connection.Query<DateTime?>("select null").First().IsNull(); } public void TestExpando() { var rows = connection.Query("select 1 A, 2 B union all select 3, 4").ToList(); ((int)rows[0].A) .IsEqualTo(1); ((int)rows[0].B) .IsEqualTo(2); ((int)rows[1].A) .IsEqualTo(3); ((int)rows[1].B) .IsEqualTo(4); } public void TestStringList() { connection.Query<string>("select * from (select 'a' as x union all select 'b' union all select 'c') as T where x in @strings", new { strings = new[] { "a", "b", "c" } }) .IsSequenceEqualTo(new[] { "a", "b", "c" }); connection.Query<string>("select * from (select 'a' as x union all select 'b' union all select 'c') as T where x in @strings", new { strings = new string[0] }) .IsSequenceEqualTo(new string[0]); } public void TestExecuteCommand() { connection.Execute(@" set nocount on create table #t(i int) set nocount off insert #t select @a a union all select @b set nocount on drop table #t", new { a = 1, b = 2 }).IsEqualTo(2); } public void TestExecuteCommandWithHybridParameters() { var p = new DynamicParameters(new { a = 1, b = 2 }); p.Add("c", dbType: DbType.Int32, direction: ParameterDirection.Output); connection.Execute(@"set @c = @a + @b", p); p.Get<int>("@c").IsEqualTo(3); } public void TestExecuteMultipleCommand() { connection.Execute("create table #t(i int)"); try { int tally = connection.Execute(@"insert #t (i) values(@a)", new[] { new { a = 1 }, new { a = 2 }, new { a = 3 }, new { a = 4 } }); int sum = connection.Query<int>("select sum(i) from #t").First(); tally.IsEqualTo(4); sum.IsEqualTo(10); } finally { connection.Execute("drop table #t"); } } class Student { public string Name { get; set; } public int Age { get; set; } } public void TestExecuteMultipleCommandStrongType() { connection.Execute("create table #t(Name nvarchar(max), Age int)"); try { int tally = connection.Execute(@"insert #t (Name,Age) values(@Name, @Age)", new List<Student> { new Student{Age = 1, Name = "sam"}, new Student{Age = 2, Name = "bob"} }); int sum = connection.Query<int>("select sum(Age) from #t").First(); tally.IsEqualTo(2); sum.IsEqualTo(3); } finally { connection.Execute("drop table #t"); } } public void TestExecuteMultipleCommandObjectArray() { connection.Execute("create table #t(i int)"); int tally = connection.Execute(@"insert #t (i) values(@a)", new object[] { new { a = 1 }, new { a = 2 }, new { a = 3 }, new { a = 4 } }); int sum = connection.Query<int>("select sum(i) from #t drop table #t").First(); tally.IsEqualTo(4); sum.IsEqualTo(10); } public void TestMassiveStrings() { var str = new string('X', 20000); connection.Query<string>("select @a", new { a = str }).First() .IsEqualTo(str); } class TestObj { public int _internal; internal int Internal { set { _internal = value; } } public int _priv; private int Priv { set { _priv = value; } } private int PrivGet { get { return _priv; } } } public void TestSetInternal() { connection.Query<TestObj>("select 10 as [Internal]").First()._internal.IsEqualTo(10); } public void TestSetPrivate() { connection.Query<TestObj>("select 10 as [Priv]").First()._priv.IsEqualTo(10); } public void TestExpandWithNullableFields() { var row = connection.Query("select null A, 2 B").Single(); ((int?)row.A) .IsNull(); ((int?)row.B) .IsEqualTo(2); } public void TestEnumeration() { var en = connection.Query<int>("select 1 as one union all select 2 as one", buffered: false); var i = en.GetEnumerator(); i.MoveNext(); bool gotException = false; try { var x = connection.Query<int>("select 1 as one", buffered: false).First(); } catch (Exception) { gotException = true; } while (i.MoveNext()) { } // should not exception, since enumerated en = connection.Query<int>("select 1 as one", buffered: false); gotException.IsTrue(); } public void TestEnumerationDynamic() { var en = connection.Query("select 1 as one union all select 2 as one", buffered: false); var i = en.GetEnumerator(); i.MoveNext(); bool gotException = false; try { var x = connection.Query("select 1 as one", buffered: false).First(); } catch (Exception) { gotException = true; } while (i.MoveNext()) { } // should not exception, since enumertated en = connection.Query("select 1 as one", buffered: false); gotException.IsTrue(); } public void TestNakedBigInt() { long foo = 12345; var result = connection.Query<long>("select @foo", new { foo }).Single(); foo.IsEqualTo(result); } public void TestBigIntMember() { long foo = 12345; var result = connection.Query<WithBigInt>(@" declare @bar table(Value bigint) insert @bar values (@foo) select * from @bar", new { foo }).Single(); result.Value.IsEqualTo(foo); } class WithBigInt { public long Value { get; set; } } class User { public int Id { get; set; } public string Name { get; set; } } class Post { public int Id { get; set; } public User Owner { get; set; } public string Content { get; set; } public Comment Comment { get; set; } } public void TestMultiMap() { var createSql = @" create table #Users (Id int, Name varchar(20)) create table #Posts (Id int, OwnerId int, Content varchar(20)) insert #Users values(99, 'Sam') insert #Users values(2, 'I am') insert #Posts values(1, 99, 'Sams Post1') insert #Posts values(2, 99, 'Sams Post2') insert #Posts values(3, null, 'no ones post') "; connection.Execute(createSql); try { var sql = @"select * from #Posts p left join #Users u on u.Id = p.OwnerId Order by p.Id"; var data = connection.Query<Post, User, Post>(sql, (post, user) => { post.Owner = user; return post; }).ToList(); var p = data.First(); p.Content.IsEqualTo("Sams Post1"); p.Id.IsEqualTo(1); p.Owner.Name.IsEqualTo("Sam"); p.Owner.Id.IsEqualTo(99); data[2].Owner.IsNull(); } finally { connection.Execute("drop table #Users drop table #Posts"); } } class ReviewBoard { public int Id { get; set; } public string Name { get; set; } public User User1 { get; set; } public User User2 { get; set; } public User User3 { get; set; } public User User4 { get; set; } public User User5 { get; set; } public User User6 { get; set; } public User User7 { get; set; } public User User8 { get; set; } public User User9 { get; set; } } public void TestMultiMapArbitraryMaps() { // please excuse the trite example, but it is easier to follow than a more real-world one var createSql = @" create table #ReviewBoards (Id int, Name varchar(20), User1Id int, User2Id int, User3Id int, User4Id int, User5Id int, User6Id int, User7Id int, User8Id int, User9Id int) create table #Users (Id int, Name varchar(20)) insert #Users values(1, 'User 1') insert #Users values(2, 'User 2') insert #Users values(3, 'User 3') insert #Users values(4, 'User 4') insert #Users values(5, 'User 5') insert #Users values(6, 'User 6') insert #Users values(7, 'User 7') insert #Users values(8, 'User 8') insert #Users values(9, 'User 9') insert #ReviewBoards values(1, 'Review Board 1', 1, 2, 3, 4, 5, 6, 7, 8, 9) "; connection.Execute(createSql); try { var sql = @" select rb.Id, rb.Name, u1.*, u2.*, u3.*, u4.*, u5.*, u6.*, u7.*, u8.*, u9.* from #ReviewBoards rb inner join #Users u1 on u1.Id = rb.User1Id inner join #Users u2 on u2.Id = rb.User2Id inner join #Users u3 on u3.Id = rb.User3Id inner join #Users u4 on u4.Id = rb.User4Id inner join #Users u5 on u5.Id = rb.User5Id inner join #Users u6 on u6.Id = rb.User6Id inner join #Users u7 on u7.Id = rb.User7Id inner join #Users u8 on u8.Id = rb.User8Id inner join #Users u9 on u9.Id = rb.User9Id "; var types = new[] { typeof(ReviewBoard), typeof(User), typeof(User), typeof(User), typeof(User), typeof(User), typeof(User), typeof(User), typeof(User), typeof(User) }; Func<object[], ReviewBoard> mapper = (objects) => { var board = (ReviewBoard)objects[0]; board.User1 = (User)objects[1]; board.User2 = (User)objects[2]; board.User3 = (User)objects[3]; board.User4 = (User)objects[4]; board.User5 = (User)objects[5]; board.User6 = (User)objects[6]; board.User7 = (User)objects[7]; board.User8 = (User)objects[8]; board.User9 = (User)objects[9]; return board; }; var data = connection.Query<ReviewBoard>(sql, types, mapper).ToList(); var p = data.First(); p.Id.IsEqualTo(1); p.Name.IsEqualTo("Review Board 1"); p.User1.Id.IsEqualTo(1); p.User2.Id.IsEqualTo(2); p.User3.Id.IsEqualTo(3); p.User4.Id.IsEqualTo(4); p.User5.Id.IsEqualTo(5); p.User6.Id.IsEqualTo(6); p.User7.Id.IsEqualTo(7); p.User8.Id.IsEqualTo(8); p.User9.Id.IsEqualTo(9); p.User1.Name.IsEqualTo("User 1"); p.User2.Name.IsEqualTo("User 2"); p.User3.Name.IsEqualTo("User 3"); p.User4.Name.IsEqualTo("User 4"); p.User5.Name.IsEqualTo("User 5"); p.User6.Name.IsEqualTo("User 6"); p.User7.Name.IsEqualTo("User 7"); p.User8.Name.IsEqualTo("User 8"); p.User9.Name.IsEqualTo("User 9"); } finally { connection.Execute("drop table #Users drop table #ReviewBoards"); } } public void TestMultiMapGridReader() { var createSql = @" create table #Users (Id int, Name varchar(20)) create table #Posts (Id int, OwnerId int, Content varchar(20)) insert #Users values(99, 'Sam') insert #Users values(2, 'I am') insert #Posts values(1, 99, 'Sams Post1') insert #Posts values(2, 99, 'Sams Post2') insert #Posts values(3, null, 'no ones post') "; connection.Execute(createSql); var sql = @"select p.*, u.Id, u.Name + '0' Name from #Posts p left join #Users u on u.Id = p.OwnerId Order by p.Id select p.*, u.Id, u.Name + '1' Name from #Posts p left join #Users u on u.Id = p.OwnerId Order by p.Id "; var grid = connection.QueryMultiple(sql); for (int i = 0; i < 2; i++) { var data = grid.Read<Post, User, Post>((post, user) => { post.Owner = user; return post; }).ToList(); var p = data.First(); p.Content.IsEqualTo("Sams Post1"); p.Id.IsEqualTo(1); p.Owner.Name.IsEqualTo("Sam" + i); p.Owner.Id.IsEqualTo(99); data[2].Owner.IsNull(); } connection.Execute("drop table #Users drop table #Posts"); } public void TestQueryMultipleBuffered() { using (var grid = connection.QueryMultiple("select 1; select 2; select @x; select 4", new { x = 3 })) { var a = grid.Read<int>(); var b = grid.Read<int>(); var c = grid.Read<int>(); var d = grid.Read<int>(); a.Single().Equals(1); b.Single().Equals(2); c.Single().Equals(3); d.Single().Equals(4); } } public void TestQueryMultipleNonBufferedIncorrectOrder() { using (var grid = connection.QueryMultiple("select 1; select 2; select @x; select 4", new { x = 3 })) { var a = grid.Read<int>(false); try { var b = grid.Read<int>(false); throw new InvalidOperationException(); // should have thrown } catch (InvalidOperationException) { // that's expected } } } public void TestQueryMultipleNonBufferedCcorrectOrder() { using (var grid = connection.QueryMultiple("select 1; select 2; select @x; select 4", new { x = 3 })) { var a = grid.Read<int>(false).Single(); var b = grid.Read<int>(false).Single(); var c = grid.Read<int>(false).Single(); var d = grid.Read<int>(false).Single(); a.Equals(1); b.Equals(2); c.Equals(3); d.Equals(4); } } public void TestMultiMapDynamic() { var createSql = @" create table #Users (Id int, Name varchar(20)) create table #Posts (Id int, OwnerId int, Content varchar(20)) insert #Users values(99, 'Sam') insert #Users values(2, 'I am') insert #Posts values(1, 99, 'Sams Post1') insert #Posts values(2, 99, 'Sams Post2') insert #Posts values(3, null, 'no ones post') "; connection.Execute(createSql); var sql = @"select * from #Posts p left join #Users u on u.Id = p.OwnerId Order by p.Id"; var data = connection.Query<dynamic, dynamic, dynamic>(sql, (post, user) => { post.Owner = user; return post; }).ToList(); var p = data.First(); // hairy extension method support for dynamics ((string)p.Content).IsEqualTo("Sams Post1"); ((int)p.Id).IsEqualTo(1); ((string)p.Owner.Name).IsEqualTo("Sam"); ((int)p.Owner.Id).IsEqualTo(99); ((object)data[2].Owner).IsNull(); connection.Execute("drop table #Users drop table #Posts"); } class Product { public int Id { get; set; } public string Name { get; set; } public Category Category { get; set; } } class Category { public int Id { get; set; } public string Name { get; set; } public string Description { get; set; } } public void TestMultiMapWithSplit() // http://stackoverflow.com/q/6056778/23354 { var sql = @"select 1 as id, 'abc' as name, 2 as id, 'def' as name"; var product = connection.Query<Product, Category, Product>(sql, (prod, cat) => { prod.Category = cat; return prod; }).First(); // assertions product.Id.IsEqualTo(1); product.Name.IsEqualTo("abc"); product.Category.Id.IsEqualTo(2); product.Category.Name.IsEqualTo("def"); } public void TestMultiMapWithSplitWithNullValue() // http://stackoverflow.com/q/10744728/449906 { var sql = @"select 1 as id, 'abc' as name, NULL as description, 'def' as name"; var product = connection.Query<Product, Category, Product>(sql, (prod, cat) => { prod.Category = cat; return prod; }, splitOn: "description").First(); // assertions product.Id.IsEqualTo(1); product.Name.IsEqualTo("abc"); product.Category.IsNull(); } public void TestMultiMapWithSplitWithNullValueAndSpoofColumn() // http://stackoverflow.com/q/10744728/449906 { var sql = @"select 1 as id, 'abc' as name, 1 as spoof, NULL as description, 'def' as name"; var product = connection.Query<Product, Category, Product>(sql, (prod, cat) => { prod.Category = cat; return prod; }, splitOn: "spoof").First(); // assertions product.Id.IsEqualTo(1); product.Name.IsEqualTo("abc"); product.Category.IsNotNull(); product.Category.Id.IsEqualTo(0); product.Category.Name.IsEqualTo("def"); product.Category.Description.IsNull(); } public void TestFieldsAndPrivates() { var data = connection.Query<TestFieldCaseAndPrivatesEntity>( @"select a=1,b=2,c=3,d=4,f='5'").Single(); data.a.IsEqualTo(1); data.GetB().IsEqualTo(2); data.c.IsEqualTo(3); data.GetD().IsEqualTo(4); data.e.IsEqualTo(5); } #if EXTERNALS public void ExecuteReader() { var dt = new DataTable(); dt.Load(connection.ExecuteReader("select 3 as [three], 4 as [four]")); dt.Columns.Count.IsEqualTo(2); dt.Columns[0].ColumnName.IsEqualTo("three"); dt.Columns[1].ColumnName.IsEqualTo("four"); dt.Rows.Count.IsEqualTo(1); ((int)dt.Rows[0][0]).IsEqualTo(3); ((int)dt.Rows[0][1]).IsEqualTo(4); } #endif private class TestFieldCaseAndPrivatesEntity { public int a { get; set; } private int b { get; set; } public int GetB() { return b; } public int c = 0; private int d = 0; public int GetD() { return d; } public int e { get; set; } private string f { get { return e.ToString(); } set { e = int.Parse(value); } } } public void TestMultiReaderBasic() { var sql = @"select 1 as Id union all select 2 as Id select 'abc' as name select 1 as Id union all select 2 as Id"; int i, j; string s; using (var multi = connection.QueryMultiple(sql)) { i = multi.Read<int>().First(); s = multi.Read<string>().Single(); j = multi.Read<int>().Sum(); } Assert.IsEqualTo(i, 1); Assert.IsEqualTo(s, "abc"); Assert.IsEqualTo(j, 3); } public void TestMultiMappingVariations() { var sql = @"select 1 as Id, 'a' as Content, 2 as Id, 'b' as Content, 3 as Id, 'c' as Content, 4 as Id, 'd' as Content, 5 as Id, 'e' as Content"; var order = connection.Query<dynamic, dynamic, dynamic, dynamic>(sql, (o, owner, creator) => { o.Owner = owner; o.Creator = creator; return o; }).First(); Assert.IsEqualTo(order.Id, 1); Assert.IsEqualTo(order.Content, "a"); Assert.IsEqualTo(order.Owner.Id, 2); Assert.IsEqualTo(order.Owner.Content, "b"); Assert.IsEqualTo(order.Creator.Id, 3); Assert.IsEqualTo(order.Creator.Content, "c"); order = connection.Query<dynamic, dynamic, dynamic, dynamic, dynamic>(sql, (o, owner, creator, address) => { o.Owner = owner; o.Creator = creator; o.Owner.Address = address; return o; }).First(); Assert.IsEqualTo(order.Id, 1); Assert.IsEqualTo(order.Content, "a"); Assert.IsEqualTo(order.Owner.Id, 2); Assert.IsEqualTo(order.Owner.Content, "b"); Assert.IsEqualTo(order.Creator.Id, 3); Assert.IsEqualTo(order.Creator.Content, "c"); Assert.IsEqualTo(order.Owner.Address.Id, 4); Assert.IsEqualTo(order.Owner.Address.Content, "d"); order = connection.Query<dynamic, dynamic, dynamic, dynamic, dynamic, dynamic>(sql, (a, b, c, d, e) => { a.B = b; a.C = c; a.C.D = d; a.E = e; return a; }).First(); Assert.IsEqualTo(order.Id, 1); Assert.IsEqualTo(order.Content, "a"); Assert.IsEqualTo(order.B.Id, 2); Assert.IsEqualTo(order.B.Content, "b"); Assert.IsEqualTo(order.C.Id, 3); Assert.IsEqualTo(order.C.Content, "c"); Assert.IsEqualTo(order.C.D.Id, 4); Assert.IsEqualTo(order.C.D.Content, "d"); Assert.IsEqualTo(order.E.Id, 5); Assert.IsEqualTo(order.E.Content, "e"); } class InheritanceTest1 { public string Base1 { get; set; } public string Base2 { get; private set; } } class InheritanceTest2 : InheritanceTest1 { public string Derived1 { get; set; } public string Derived2 { get; private set; } } public void TestInheritance() { // Test that inheritance works. var list = connection.Query<InheritanceTest2>("select 'One' as Derived1, 'Two' as Derived2, 'Three' as Base1, 'Four' as Base2"); list.First().Derived1.IsEqualTo("One"); list.First().Derived2.IsEqualTo("Two"); list.First().Base1.IsEqualTo("Three"); list.First().Base2.IsEqualTo("Four"); } public class PostCE { public int ID { get; set; } public string Title { get; set; } public string Body { get; set; } public AuthorCE Author { get; set; } } public class AuthorCE { public int ID { get; set; } public string Name { get; set; } } #if EXTERNALS public void MultiRSSqlCE() { if (File.Exists("Test.sdf")) File.Delete("Test.sdf"); var cnnStr = "Data Source = Test.sdf;"; var engine = new SqlCeEngine(cnnStr); engine.CreateDatabase(); using (var cnn = new SqlCeConnection(cnnStr)) { cnn.Open(); cnn.Execute("create table Posts (ID int, Title nvarchar(50), Body nvarchar(50), AuthorID int)"); cnn.Execute("create table Authors (ID int, Name nvarchar(50))"); cnn.Execute("insert Posts values (1,'title','body',1)"); cnn.Execute("insert Posts values(2,'title2','body2',null)"); cnn.Execute("insert Authors values(1,'sam')"); var data = cnn.Query<PostCE, AuthorCE, PostCE>(@"select * from Posts p left join Authors a on a.ID = p.AuthorID", (post, author) => { post.Author = author; return post; }).ToList(); var firstPost = data.First(); firstPost.Title.IsEqualTo("title"); firstPost.Author.Name.IsEqualTo("sam"); data[1].Author.IsNull(); cnn.Close(); } } #endif enum TestEnum : byte { Bla = 1 } class TestEnumClass { public TestEnum? EnumEnum { get; set; } } class TestEnumClassNoNull { public TestEnum EnumEnum { get; set; } } public void TestEnumWeirdness() { connection.Query<TestEnumClass>("select null as [EnumEnum]").First().EnumEnum.IsEqualTo(null); connection.Query<TestEnumClass>("select cast(1 as tinyint) as [EnumEnum]").First().EnumEnum.IsEqualTo(TestEnum.Bla); } public void TestEnumStrings() { connection.Query<TestEnumClassNoNull>("select 'BLA' as [EnumEnum]").First().EnumEnum.IsEqualTo(TestEnum.Bla); connection.Query<TestEnumClassNoNull>("select 'bla' as [EnumEnum]").First().EnumEnum.IsEqualTo(TestEnum.Bla); connection.Query<TestEnumClass>("select 'BLA' as [EnumEnum]").First().EnumEnum.IsEqualTo(TestEnum.Bla); connection.Query<TestEnumClass>("select 'bla' as [EnumEnum]").First().EnumEnum.IsEqualTo(TestEnum.Bla); } public void TestSupportForDynamicParameters() { var p = new DynamicParameters(); p.Add("name", "bob"); p.Add("age", dbType: DbType.Int32, direction: ParameterDirection.Output); connection.Query<string>("set @age = 11 select @name", p).First().IsEqualTo("bob"); p.Get<int>("age").IsEqualTo(11); } public void TestSupportForDynamicParametersOutputExpressions() { var bob = new Person { Name = "bob", PersonId = 1, Address = new Address { PersonId = 2 } }; var p = new DynamicParameters(bob); p.Output(bob, b => b.PersonId); p.Output(bob, b => b.Occupation); p.Output(bob, b => b.NumberOfLegs); p.Output(bob, b => b.Address.Name); p.Output(bob, b => b.Address.PersonId); connection.Execute(@" SET @Occupation = 'grillmaster' SET @PersonId = @PersonId + 1 SET @NumberOfLegs = @NumberOfLegs - 1 SET @AddressName = 'bobs burgers' SET @AddressPersonId = @PersonId", p); bob.Occupation.IsEqualTo("grillmaster"); bob.PersonId.IsEqualTo(2); bob.NumberOfLegs.IsEqualTo(1); bob.Address.Name.IsEqualTo("bobs burgers"); bob.Address.PersonId.IsEqualTo(2); } public void TestSupportForDynamicParametersOutputExpressions_Scalar() { using (var connection = Program.GetOpenConnection()) { var bob = new Person { Name = "bob", PersonId = 1, Address = new Address { PersonId = 2 } }; var p = new DynamicParameters(bob); p.Output(bob, b => b.PersonId); p.Output(bob, b => b.Occupation); p.Output(bob, b => b.NumberOfLegs); p.Output(bob, b => b.Address.Name); p.Output(bob, b => b.Address.PersonId); var result = (int)connection.ExecuteScalar(@" SET @Occupation = 'grillmaster' SET @PersonId = @PersonId + 1 SET @NumberOfLegs = @NumberOfLegs - 1 SET @AddressName = 'bobs burgers' SET @AddressPersonId = @PersonId select 42", p); bob.Occupation.IsEqualTo("grillmaster"); bob.PersonId.IsEqualTo(2); bob.NumberOfLegs.IsEqualTo(1); bob.Address.Name.IsEqualTo("bobs burgers"); bob.Address.PersonId.IsEqualTo(2); result.IsEqualTo(42); } } public void TestSupportForDynamicParametersOutputExpressions_Query_Buffered() { using (var connection = Program.GetOpenConnection()) { var bob = new Person { Name = "bob", PersonId = 1, Address = new Address { PersonId = 2 } }; var p = new DynamicParameters(bob); p.Output(bob, b => b.PersonId); p.Output(bob, b => b.Occupation); p.Output(bob, b => b.NumberOfLegs); p.Output(bob, b => b.Address.Name); p.Output(bob, b => b.Address.PersonId); var result = connection.Query<int>(@" SET @Occupation = 'grillmaster' SET @PersonId = @PersonId + 1 SET @NumberOfLegs = @NumberOfLegs - 1 SET @AddressName = 'bobs burgers' SET @AddressPersonId = @PersonId select 42", p, buffered: true).Single(); bob.Occupation.IsEqualTo("grillmaster"); bob.PersonId.IsEqualTo(2); bob.NumberOfLegs.IsEqualTo(1); bob.Address.Name.IsEqualTo("bobs burgers"); bob.Address.PersonId.IsEqualTo(2); result.IsEqualTo(42); } } public void TestSupportForDynamicParametersOutputExpressions_Query_NonBuffered() { using (var connection = Program.GetOpenConnection()) { var bob = new Person { Name = "bob", PersonId = 1, Address = new Address { PersonId = 2 } }; var p = new DynamicParameters(bob); p.Output(bob, b => b.PersonId); p.Output(bob, b => b.Occupation); p.Output(bob, b => b.NumberOfLegs); p.Output(bob, b => b.Address.Name); p.Output(bob, b => b.Address.PersonId); var result = connection.Query<int>(@" SET @Occupation = 'grillmaster' SET @PersonId = @PersonId + 1 SET @NumberOfLegs = @NumberOfLegs - 1 SET @AddressName = 'bobs burgers' SET @AddressPersonId = @PersonId select 42", p, buffered: false).Single(); bob.Occupation.IsEqualTo("grillmaster"); bob.PersonId.IsEqualTo(2); bob.NumberOfLegs.IsEqualTo(1); bob.Address.Name.IsEqualTo("bobs burgers"); bob.Address.PersonId.IsEqualTo(2); result.IsEqualTo(42); } } public void TestSupportForDynamicParametersOutputExpressions_QueryMultiple() { using (var connection = Program.GetOpenConnection()) { var bob = new Person { Name = "bob", PersonId = 1, Address = new Address { PersonId = 2 } }; var p = new DynamicParameters(bob); p.Output(bob, b => b.PersonId); p.Output(bob, b => b.Occupation); p.Output(bob, b => b.NumberOfLegs); p.Output(bob, b => b.Address.Name); p.Output(bob, b => b.Address.PersonId); int x, y; using (var multi = connection.QueryMultiple(@" SET @Occupation = 'grillmaster' SET @PersonId = @PersonId + 1 SET @NumberOfLegs = @NumberOfLegs - 1 SET @AddressName = 'bobs burgers' select 42 select 17 SET @AddressPersonId = @PersonId", p)) { x = multi.Read<int>().Single(); y = multi.Read<int>().Single(); } bob.Occupation.IsEqualTo("grillmaster"); bob.PersonId.IsEqualTo(2); bob.NumberOfLegs.IsEqualTo(1); bob.Address.Name.IsEqualTo("bobs burgers"); bob.Address.PersonId.IsEqualTo(2); x.IsEqualTo(42); y.IsEqualTo(17); } } public void TestSupportForExpandoObjectParameters() { dynamic p = new ExpandoObject(); p.name = "bob"; object parameters = p; string result = connection.Query<string>("select @name", parameters).First(); result.IsEqualTo("bob"); } public void TestProcSupport() { var p = new DynamicParameters(); p.Add("a", 11); p.Add("b", dbType: DbType.Int32, direction: ParameterDirection.Output); p.Add("c", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue); connection.Execute(@"create proc #TestProc @a int, @b int output as begin set @b = 999 select 1111 return @a end"); connection.Query<int>("#TestProc", p, commandType: CommandType.StoredProcedure).First().IsEqualTo(1111); p.Get<int>("c").IsEqualTo(11); p.Get<int>("b").IsEqualTo(999); } public void TestDbString() { var obj = connection.Query("select datalength(@a) as a, datalength(@b) as b, datalength(@c) as c, datalength(@d) as d, datalength(@e) as e, datalength(@f) as f", new { a = new DbString { Value = "abcde", IsFixedLength = true, Length = 10, IsAnsi = true }, b = new DbString { Value = "abcde", IsFixedLength = true, Length = 10, IsAnsi = false }, c = new DbString { Value = "abcde", IsFixedLength = false, Length = 10, IsAnsi = true }, d = new DbString { Value = "abcde", IsFixedLength = false, Length = 10, IsAnsi = false }, e = new DbString { Value = "abcde", IsAnsi = true }, f = new DbString { Value = "abcde", IsAnsi = false }, }).First(); ((int)obj.a).IsEqualTo(10); ((int)obj.b).IsEqualTo(20); ((int)obj.c).IsEqualTo(5); ((int)obj.d).IsEqualTo(10); ((int)obj.e).IsEqualTo(5); ((int)obj.f).IsEqualTo(10); } class Person { public int PersonId { get; set; } public string Name { get; set; } public string Occupation { get; private set; } public int NumberOfLegs = 2; public Address Address { get; set; } } class Address { public int AddressId { get; set; } public string Name { get; set; } public int PersonId { get; set; } } class Extra { public int Id { get; set; } public string Name { get; set; } } public void TestFlexibleMultiMapping() { var sql = @"select 1 as PersonId, 'bob' as Name, 2 as AddressId, 'abc street' as Name, 1 as PersonId, 3 as Id, 'fred' as Name "; var personWithAddress = connection.Query<Person, Address, Extra, Tuple<Person, Address, Extra>> (sql, (p, a, e) => Tuple.Create(p, a, e), splitOn: "AddressId,Id").First(); personWithAddress.Item1.PersonId.IsEqualTo(1); personWithAddress.Item1.Name.IsEqualTo("bob"); personWithAddress.Item2.AddressId.IsEqualTo(2); personWithAddress.Item2.Name.IsEqualTo("abc street"); personWithAddress.Item2.PersonId.IsEqualTo(1); personWithAddress.Item3.Id.IsEqualTo(3); personWithAddress.Item3.Name.IsEqualTo("fred"); } public void TestMultiMappingWithSplitOnSpaceBetweenCommas() { var sql = @"select 1 as PersonId, 'bob' as Name, 2 as AddressId, 'abc street' as Name, 1 as PersonId, 3 as Id, 'fred' as Name "; var personWithAddress = connection.Query<Person, Address, Extra, Tuple<Person, Address, Extra>> (sql, (p, a, e) => Tuple.Create(p, a, e), splitOn: "AddressId, Id").First(); personWithAddress.Item1.PersonId.IsEqualTo(1); personWithAddress.Item1.Name.IsEqualTo("bob"); personWithAddress.Item2.AddressId.IsEqualTo(2); personWithAddress.Item2.Name.IsEqualTo("abc street"); personWithAddress.Item2.PersonId.IsEqualTo(1); personWithAddress.Item3.Id.IsEqualTo(3); personWithAddress.Item3.Name.IsEqualTo("fred"); } public void TestMultiMappingWithNonReturnedProperty() { var sql = @"select 1 as PostId, 'Title' as Title, 2 as BlogId, 'Blog' as Title"; var postWithBlog = connection.Query<Post_DupeProp, Blog_DupeProp, Post_DupeProp>(sql, (p, b) => { p.Blog = b; return p; }, splitOn: "BlogId").First(); postWithBlog.PostId.IsEqualTo(1); postWithBlog.Title.IsEqualTo("Title"); postWithBlog.Blog.BlogId.IsEqualTo(2); postWithBlog.Blog.Title.IsEqualTo("Blog"); } class Post_DupeProp { public int PostId { get; set; } public string Title { get; set; } public int BlogId { get; set; } public Blog_DupeProp Blog { get; set; } } class Blog_DupeProp { public int BlogId { get; set; } public string Title { get; set; } } public void TestFastExpandoSupportsIDictionary() { var row = connection.Query("select 1 A, 'two' B").First() as IDictionary<string, object>; row["A"].IsEqualTo(1); row["B"].IsEqualTo("two"); } class PrivateDan { public int Shadow { get; set; } private string ShadowInDB { set { Shadow = value == "one" ? 1 : 0; } } } public void TestDapperSetsPrivates() { connection.Query<PrivateDan>("select 'one' ShadowInDB").First().Shadow.IsEqualTo(1); } class IntDynamicParam : Dapper.SqlMapper.IDynamicParameters { IEnumerable<int> numbers; public IntDynamicParam(IEnumerable<int> numbers) { this.numbers = numbers; } public void AddParameters(IDbCommand command, Dapper.SqlMapper.Identity identity) { var sqlCommand = (SqlCommand)command; sqlCommand.CommandType = CommandType.StoredProcedure; List<Microsoft.SqlServer.Server.SqlDataRecord> number_list = new List<Microsoft.SqlServer.Server.SqlDataRecord>(); // 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. Microsoft.SqlServer.Server.SqlDataRecord rec = new Microsoft.SqlServer.Server.SqlDataRecord(tvp_definition); rec.SetInt32(0, n); // Set the value. number_list.Add(rec); // Add it to the list. } // Add the table parameter. var p = sqlCommand.Parameters.Add("ints", SqlDbType.Structured); p.Direction = ParameterDirection.Input; p.TypeName = "int_list_type"; p.Value = number_list; } } #if EXTERNALS // SQL Server specific test to demonstrate TVP public void TestTVP() { try { connection.Execute("CREATE TYPE int_list_type AS TABLE (n int NOT NULL PRIMARY KEY)"); connection.Execute("CREATE PROC get_ints @ints int_list_type READONLY AS select * from @ints"); var nums = connection.Query<int>("get_ints", new IntDynamicParam(new int[] { 1, 2, 3 })).ToList(); nums[0].IsEqualTo(1); nums[1].IsEqualTo(2); nums[2].IsEqualTo(3); nums.Count.IsEqualTo(3); } finally { try { connection.Execute("DROP PROC get_ints"); } finally { connection.Execute("DROP TYPE int_list_type"); } } } class DynamicParameterWithIntTVP : Dapper.DynamicParameters, Dapper.SqlMapper.IDynamicParameters { IEnumerable<int> numbers; public DynamicParameterWithIntTVP(IEnumerable<int> numbers) { this.numbers = numbers; } public new void AddParameters(IDbCommand command, Dapper.SqlMapper.Identity identity) { base.AddParameters(command, identity); var sqlCommand = (SqlCommand)command; sqlCommand.CommandType = CommandType.StoredProcedure; List<Microsoft.SqlServer.Server.SqlDataRecord> number_list = new List<Microsoft.SqlServer.Server.SqlDataRecord>(); // 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. Microsoft.SqlServer.Server.SqlDataRecord rec = new Microsoft.SqlServer.Server.SqlDataRecord(tvp_definition); rec.SetInt32(0, n); // Set the value. number_list.Add(rec); // Add it to the list. } // Add the table parameter. var p = sqlCommand.Parameters.Add("ints", SqlDbType.Structured); p.Direction = ParameterDirection.Input; p.TypeName = "int_list_type"; p.Value = number_list; } } public void TestTVPWithAdditionalParams() { try { connection.Execute("CREATE TYPE int_list_type AS TABLE (n int NOT NULL PRIMARY KEY)"); connection.Execute("CREATE PROC get_values @ints int_list_type READONLY, @stringParam varchar(20), @dateParam datetime AS select i.*, @stringParam as stringParam, @dateParam as dateParam from @ints i"); var dynamicParameters = new DynamicParameterWithIntTVP(new int[] { 1, 2, 3 }); dynamicParameters.AddDynamicParams(new { stringParam = "stringParam", dateParam = new DateTime(2012, 1, 1) }); var results = connection.Query("get_values", dynamicParameters, commandType: CommandType.StoredProcedure).ToList(); results.Count.IsEqualTo(3); for (int i = 0; i < results.Count; i++) { var result = results[i]; Assert.IsEqualTo(i + 1, result.n); Assert.IsEqualTo("stringParam", result.stringParam); Assert.IsEqualTo(new DateTime(2012, 1, 1), result.dateParam); } } finally { try { connection.Execute("DROP PROC get_values"); } finally { connection.Execute("DROP TYPE int_list_type"); } } } #endif class IntCustomParam : Dapper.SqlMapper.ICustomQueryParameter { IEnumerable<int> numbers; public IntCustomParam(IEnumerable<int> numbers) { this.numbers = numbers; } public void AddParameter(IDbCommand command, string name) { var sqlCommand = (SqlCommand)command; sqlCommand.CommandType = CommandType.StoredProcedure; List<Microsoft.SqlServer.Server.SqlDataRecord> number_list = new List<Microsoft.SqlServer.Server.SqlDataRecord>(); // 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. Microsoft.SqlServer.Server.SqlDataRecord rec = new Microsoft.SqlServer.Server.SqlDataRecord(tvp_definition); rec.SetInt32(0, n); // Set the value. number_list.Add(rec); // Add it to the list. } // Add the table parameter. var p = sqlCommand.Parameters.Add(name, SqlDbType.Structured); p.Direction = ParameterDirection.Input; p.TypeName = "int_list_type"; p.Value = number_list; } } #if EXTERNALS public void TestTVPWithAnonymousObject() { 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 nums = connection.Query<int>("get_ints", new { integers = new IntCustomParam(new int[] { 1, 2, 3 }) }, commandType: CommandType.StoredProcedure).ToList(); nums[0].IsEqualTo(1); nums[1].IsEqualTo(2); nums[2].IsEqualTo(3); nums.Count.IsEqualTo(3); } finally { try { connection.Execute("DROP PROC get_ints"); } finally { connection.Execute("DROP TYPE int_list_type"); } } } #endif class Parent { public int Id { get; set; } public readonly List<Child> Children = new List<Child>(); } class Child { public int Id { get; set; } } public void ParentChildIdentityAssociations() { var lookup = new Dictionary<int, Parent>(); var parents = connection.Query<Parent, Child, Parent>(@"select 1 as [Id], 1 as [Id] union all select 1,2 union all select 2,3 union all select 1,4 union all select 3,5", (parent, child) => { Parent found; if (!lookup.TryGetValue(parent.Id, out found)) { lookup.Add(parent.Id, found = parent); } found.Children.Add(child); return found; }).Distinct().ToDictionary(p => p.Id); parents.Count().IsEqualTo(3); parents[1].Children.Select(c => c.Id).SequenceEqual(new[] { 1, 2, 4 }).IsTrue(); parents[2].Children.Select(c => c.Id).SequenceEqual(new[] { 3 }).IsTrue(); parents[3].Children.Select(c => c.Id).SequenceEqual(new[] { 5 }).IsTrue(); } /* TODO: * public void TestMagicParam() { // magic params allow you to pass in single params without using an anon class // this test fails for now, but I would like to support a single param by parsing the sql with regex and remapping. var first = connection.Query("select @a as a", 1).First(); Assert.IsEqualTo(first.a, 1); } * */ class WithBizarreData { public GenericUriParser Foo { get; set; } public int Bar { get; set; } } public void TestUnexpectedDataMessage() { string msg = null; try { connection.Query<int>("select count(1) where 1 = @Foo", new WithBizarreData { Foo = new GenericUriParser(GenericUriParserOptions.Default), Bar = 23 }).First(); } catch (Exception ex) { msg = ex.Message; } msg.IsEqualTo("The member Foo of type System.GenericUriParser cannot be used as a parameter value"); } public void TestUnexpectedButFilteredDataMessage() { int i = connection.Query<int>("select @Bar", new WithBizarreData { Foo = new GenericUriParser(GenericUriParserOptions.Default), Bar = 23 }).Single(); i.IsEqualTo(23); } class WithCharValue { public char Value { get; set; } public char? ValueNullable { get; set; } } public void TestCharInputAndOutput() { const char test = '〠'; char c = connection.Query<char>("select @c", new { c = test }).Single(); c.IsEqualTo(test); var obj = connection.Query<WithCharValue>("select @Value as Value", new WithCharValue { Value = c }).Single(); obj.Value.IsEqualTo(test); } public void TestNullableCharInputAndOutputNonNull() { char? test = '〠'; char? c = connection.Query<char?>("select @c", new { c = test }).Single(); c.IsEqualTo(test); var obj = connection.Query<WithCharValue>("select @ValueNullable as ValueNullable", new WithCharValue { ValueNullable = c }).Single(); obj.ValueNullable.IsEqualTo(test); } public void TestNullableCharInputAndOutputNull() { char? test = null; char? c = connection.Query<char?>("select @c", new { c = test }).Single(); c.IsEqualTo(test); var obj = connection.Query<WithCharValue>("select @ValueNullable as ValueNullable", new WithCharValue { ValueNullable = c }).Single(); obj.ValueNullable.IsEqualTo(test); } public void TestInvalidSplitCausesNiceError() { try { connection.Query<User, User, User>("select 1 A, 2 B, 3 C", (x, y) => x); } catch (ArgumentException) { // expecting an app exception due to multi mapping being bodged } try { connection.Query<dynamic, dynamic, dynamic>("select 1 A, 2 B, 3 C", (x, y) => x); } catch (ArgumentException) { // expecting an app exception due to multi mapping being bodged } } class Comment { public int Id { get; set; } public string CommentData { get; set; } } public void TestMultiMapThreeTypesWithGridReader() { var createSql = @" create table #Users (Id int, Name varchar(20)) create table #Posts (Id int, OwnerId int, Content varchar(20)) create table #Comments (Id int, PostId int, CommentData varchar(20)) insert #Users values(99, 'Sam') insert #Users values(2, 'I am') insert #Posts values(1, 99, 'Sams Post1') insert #Posts values(2, 99, 'Sams Post2') insert #Posts values(3, null, 'no ones post') insert #Comments values(1, 1, 'Comment 1')"; connection.Execute(createSql); try { var sql = @"SELECT p.* FROM #Posts p select p.*, u.Id, u.Name + '0' Name, c.Id, c.CommentData from #Posts p left join #Users u on u.Id = p.OwnerId left join #Comments c on c.PostId = p.Id where p.Id = 1 Order by p.Id"; var grid = connection.QueryMultiple(sql); var post1 = grid.Read<Post>().ToList(); var post2 = grid.Read<Post, User, Comment, Post>((post, user, comment) => { post.Owner = user; post.Comment = comment; return post; }).SingleOrDefault(); post2.Comment.Id.IsEqualTo(1); post2.Owner.Id.IsEqualTo(99); } finally { connection.Execute("drop table #Users drop table #Posts drop table #Comments"); } } public class DbParams : Dapper.SqlMapper.IDynamicParameters, IEnumerable<IDbDataParameter> { private readonly List<IDbDataParameter> parameters = new List<IDbDataParameter>(); public IEnumerator<IDbDataParameter> GetEnumerator() { return parameters.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public void Add(IDbDataParameter value) { parameters.Add(value); } void Dapper.SqlMapper.IDynamicParameters.AddParameters(IDbCommand command, Dapper.SqlMapper.Identity identity) { foreach (IDbDataParameter parameter in parameters) command.Parameters.Add(parameter); } } public void TestCustomParameters() { var args = new DbParams { new SqlParameter("foo", 123), new SqlParameter("bar", "abc") }; var result = connection.Query("select Foo=@foo, Bar=@bar", args).Single(); int foo = result.Foo; string bar = result.Bar; foo.IsEqualTo(123); bar.IsEqualTo("abc"); } public void TestReadDynamicWithGridReader() { var createSql = @" create table #Users (Id int, Name varchar(20)) create table #Posts (Id int, OwnerId int, Content varchar(20)) insert #Users values(99, 'Sam') insert #Users values(2, 'I am') insert #Posts values(1, 99, 'Sams Post1') insert #Posts values(2, 99, 'Sams Post2') insert #Posts values(3, null, 'no ones post')"; try { connection.Execute(createSql); var sql = @"SELECT * FROM #Users ORDER BY Id SELECT * FROM #Posts ORDER BY Id DESC"; var grid = connection.QueryMultiple(sql); var users = grid.Read().ToList(); var posts = grid.Read().ToList(); users.Count.IsEqualTo(2); posts.Count.IsEqualTo(3); ((int)users.First().Id).IsEqualTo(2); ((int)posts.First().Id).IsEqualTo(3); } finally { connection.Execute("drop table #Users drop table #Posts"); } } public void TestDynamicParamNullSupport() { var p = new DynamicParameters(); p.Add("@b", dbType: DbType.Int32, direction: ParameterDirection.Output); connection.Execute("select @b = null", p); p.Get<int?>("@b").IsNull(); } class Foo1 { #pragma warning disable 0649 public int Id; #pragma warning restore 0649 public int BarId { get; set; } } class Bar1 { #pragma warning disable 0649 public int BarId; #pragma warning restore 0649 public string Name { get; set; } } public void TestMultiMapperIsNotConfusedWithUnorderedCols() { var result = connection.Query<Foo1, Bar1, Tuple<Foo1, Bar1>>("select 1 as Id, 2 as BarId, 3 as BarId, 'a' as Name", (f, b) => Tuple.Create(f, b), splitOn: "BarId").First(); result.Item1.Id.IsEqualTo(1); result.Item1.BarId.IsEqualTo(2); result.Item2.BarId.IsEqualTo(3); result.Item2.Name.IsEqualTo("a"); } #if EXTERNALS public void TestLinqBinaryToClass() { byte[] orig = new byte[20]; new Random(123456).NextBytes(orig); var input = new System.Data.Linq.Binary(orig); var output = connection.Query<WithBinary>("select @input as [Value]", new { input }).First().Value; output.ToArray().IsSequenceEqualTo(orig); } public void TestLinqBinaryRaw() { byte[] orig = new byte[20]; new Random(123456).NextBytes(orig); var input = new System.Data.Linq.Binary(orig); var output = connection.Query<System.Data.Linq.Binary>("select @input as [Value]", new { input }).First(); output.ToArray().IsSequenceEqualTo(orig); } class WithBinary { public System.Data.Linq.Binary Value { get; set; } } #endif class WithPrivateConstructor { public int Foo { get; set; } private WithPrivateConstructor() { } } public void TestWithNonPublicConstructor() { var output = connection.Query<WithPrivateConstructor>("select 1 as Foo").First(); output.Foo.IsEqualTo(1); } public void TestAppendingAnonClasses() { DynamicParameters p = new DynamicParameters(); p.AddDynamicParams(new { A = 1, B = 2 }); p.AddDynamicParams(new { C = 3, D = 4 }); var result = connection.Query("select @A a,@B b,@C c,@D d", p).Single(); ((int)result.a).IsEqualTo(1); ((int)result.b).IsEqualTo(2); ((int)result.c).IsEqualTo(3); ((int)result.d).IsEqualTo(4); } public void TestAppendingADictionary() { var dictionary = new Dictionary<string, object>(); dictionary.Add("A", 1); dictionary.Add("B", "two"); DynamicParameters p = new DynamicParameters(); p.AddDynamicParams(dictionary); var result = connection.Query("select @A a, @B b", p).Single(); ((int)result.a).IsEqualTo(1); ((string)result.b).IsEqualTo("two"); } public void TestAppendingAnExpandoObject() { dynamic expando = new System.Dynamic.ExpandoObject(); expando.A = 1; expando.B = "two"; DynamicParameters p = new DynamicParameters(); p.AddDynamicParams(expando); var result = connection.Query("select @A a, @B b", p).Single(); ((int)result.a).IsEqualTo(1); ((string)result.b).IsEqualTo("two"); } public void TestAppendingAList() { DynamicParameters p = new DynamicParameters(); var list = new int[] { 1, 2, 3 }; p.AddDynamicParams(new { list }); var result = connection.Query<int>("select * from (select 1 A union all select 2 union all select 3) X where A in @list", p).ToList(); result[0].IsEqualTo(1); result[1].IsEqualTo(2); result[2].IsEqualTo(3); } public void TestAppendingAListAsDictionary() { DynamicParameters p = new DynamicParameters(); var list = new int[] { 1, 2, 3 }; var args = new Dictionary<string, object>(); args.Add("ids", list); p.AddDynamicParams(args); var result = connection.Query<int>("select * from (select 1 A union all select 2 union all select 3) X where A in @ids", p).ToList(); result[0].IsEqualTo(1); result[1].IsEqualTo(2); result[2].IsEqualTo(3); } public void TestAppendingAListByName() { DynamicParameters p = new DynamicParameters(); var list = new int[] { 1, 2, 3 }; p.Add("ids", list); var result = connection.Query<int>("select * from (select 1 A union all select 2 union all select 3) X where A in @ids", p).ToList(); result[0].IsEqualTo(1); result[1].IsEqualTo(2); result[2].IsEqualTo(3); } public void TestUniqueIdentifier() { var guid = Guid.NewGuid(); var result = connection.Query<Guid>("declare @foo uniqueidentifier set @foo = @guid select @foo", new { guid }).Single(); result.IsEqualTo(guid); } public void TestNullableUniqueIdentifierNonNull() { Guid? guid = Guid.NewGuid(); var result = connection.Query<Guid?>("declare @foo uniqueidentifier set @foo = @guid select @foo", new { guid }).Single(); result.IsEqualTo(guid); } public void TestNullableUniqueIdentifierNull() { Guid? guid = null; var result = connection.Query<Guid?>("declare @foo uniqueidentifier set @foo = @guid select @foo", new { guid }).Single(); result.IsEqualTo(guid); } public void WorkDespiteHavingWrongStructColumnTypes() { var hazInt = connection.Query<CanHazInt>("select cast(1 as bigint) Value").Single(); hazInt.Value.Equals(1); } public void TestProcWithOutParameter() { connection.Execute( @"CREATE PROCEDURE #TestProcWithOutParameter @ID int output, @Foo varchar(100), @Bar int AS SET @ID = @Bar + LEN(@Foo)"); var obj = new { ID = 0, Foo = "abc", Bar = 4 }; var args = new DynamicParameters(obj); args.Add("ID", 0, direction: ParameterDirection.Output); connection.Execute("#TestProcWithOutParameter", args, commandType: CommandType.StoredProcedure); args.Get<int>("ID").IsEqualTo(7); } public void TestProcWithOutAndReturnParameter() { connection.Execute( @"CREATE PROCEDURE #TestProcWithOutAndReturnParameter @ID int output, @Foo varchar(100), @Bar int AS SET @ID = @Bar + LEN(@Foo) RETURN 42"); var obj = new { ID = 0, Foo = "abc", Bar = 4 }; var args = new DynamicParameters(obj); args.Add("ID", 0, direction: ParameterDirection.Output); args.Add("result", 0, direction: ParameterDirection.ReturnValue); connection.Execute("#TestProcWithOutAndReturnParameter", args, commandType: CommandType.StoredProcedure); args.Get<int>("ID").IsEqualTo(7); args.Get<int>("result").IsEqualTo(42); } struct CanHazInt { public int Value { get; set; } } public void TestInt16Usage() { connection.Query<short>("select cast(42 as smallint)").Single().IsEqualTo((short)42); connection.Query<short?>("select cast(42 as smallint)").Single().IsEqualTo((short?)42); connection.Query<short?>("select cast(null as smallint)").Single().IsEqualTo((short?)null); connection.Query<ShortEnum>("select cast(42 as smallint)").Single().IsEqualTo((ShortEnum)42); connection.Query<ShortEnum?>("select cast(42 as smallint)").Single().IsEqualTo((ShortEnum?)42); connection.Query<ShortEnum?>("select cast(null as smallint)").Single().IsEqualTo((ShortEnum?)null); var row = connection.Query<WithInt16Values>( "select cast(1 as smallint) as NonNullableInt16, cast(2 as smallint) as NullableInt16, cast(3 as smallint) as NonNullableInt16Enum, cast(4 as smallint) as NullableInt16Enum") .Single(); row.NonNullableInt16.IsEqualTo((short)1); row.NullableInt16.IsEqualTo((short)2); row.NonNullableInt16Enum.IsEqualTo(ShortEnum.Three); row.NullableInt16Enum.IsEqualTo(ShortEnum.Four); row = connection.Query<WithInt16Values>( "select cast(5 as smallint) as NonNullableInt16, cast(null as smallint) as NullableInt16, cast(6 as smallint) as NonNullableInt16Enum, cast(null as smallint) as NullableInt16Enum") .Single(); row.NonNullableInt16.IsEqualTo((short)5); row.NullableInt16.IsEqualTo((short?)null); row.NonNullableInt16Enum.IsEqualTo(ShortEnum.Six); row.NullableInt16Enum.IsEqualTo((ShortEnum?)null); } public void TestInt32Usage() { connection.Query<int>("select cast(42 as int)").Single().IsEqualTo((int)42); connection.Query<int?>("select cast(42 as int)").Single().IsEqualTo((int?)42); connection.Query<int?>("select cast(null as int)").Single().IsEqualTo((int?)null); connection.Query<IntEnum>("select cast(42 as int)").Single().IsEqualTo((IntEnum)42); connection.Query<IntEnum?>("select cast(42 as int)").Single().IsEqualTo((IntEnum?)42); connection.Query<IntEnum?>("select cast(null as int)").Single().IsEqualTo((IntEnum?)null); var row = connection.Query<WithInt32Values>( "select cast(1 as int) as NonNullableInt32, cast(2 as int) as NullableInt32, cast(3 as int) as NonNullableInt32Enum, cast(4 as int) as NullableInt32Enum") .Single(); row.NonNullableInt32.IsEqualTo((int)1); row.NullableInt32.IsEqualTo((int)2); row.NonNullableInt32Enum.IsEqualTo(IntEnum.Three); row.NullableInt32Enum.IsEqualTo(IntEnum.Four); row = connection.Query<WithInt32Values>( "select cast(5 as int) as NonNullableInt32, cast(null as int) as NullableInt32, cast(6 as int) as NonNullableInt32Enum, cast(null as int) as NullableInt32Enum") .Single(); row.NonNullableInt32.IsEqualTo((int)5); row.NullableInt32.IsEqualTo((int?)null); row.NonNullableInt32Enum.IsEqualTo(IntEnum.Six); row.NullableInt32Enum.IsEqualTo((IntEnum?)null); } public class WithInt16Values { public short NonNullableInt16 { get; set; } public short? NullableInt16 { get; set; } public ShortEnum NonNullableInt16Enum { get; set; } public ShortEnum? NullableInt16Enum { get; set; } } public enum ShortEnum : short { Zero = 0, One = 1, Two = 2, Three = 3, Four = 4, Five = 5, Six = 6 } public class WithInt32Values { public int NonNullableInt32 { get; set; } public int? NullableInt32 { get; set; } public IntEnum NonNullableInt32Enum { get; set; } public IntEnum? NullableInt32Enum { get; set; } } public enum IntEnum : int { Zero = 0, One = 1, Two = 2, Three = 3, Four = 4, Five = 5, Six = 6 } public void TestTransactionCommit() { try { connection.Execute("create table #TransactionTest ([ID] int, [Value] varchar(32));"); using (var transaction = connection.BeginTransaction()) { connection.Execute("insert into #TransactionTest ([ID], [Value]) values (1, 'ABC');", transaction: transaction); transaction.Commit(); } connection.Query<int>("select count(*) from #TransactionTest;").Single().IsEqualTo(1); } finally { connection.Execute("drop table #TransactionTest;"); } } public void TestTransactionRollback() { connection.Execute("create table #TransactionTest ([ID] int, [Value] varchar(32));"); try { using (var transaction = connection.BeginTransaction()) { connection.Execute("insert into #TransactionTest ([ID], [Value]) values (1, 'ABC');", transaction: transaction); transaction.Rollback(); } connection.Query<int>("select count(*) from #TransactionTest;").Single().IsEqualTo(0); } finally { connection.Execute("drop table #TransactionTest;"); } } public void TestCommandWithInheritedTransaction() { connection.Execute("create table #TransactionTest ([ID] int, [Value] varchar(32));"); try { using (var transaction = connection.BeginTransaction()) { var transactedConnection = new TransactedConnection(connection, transaction); transactedConnection.Execute("insert into #TransactionTest ([ID], [Value]) values (1, 'ABC');"); transaction.Rollback(); } connection.Query<int>("select count(*) from #TransactionTest;").Single().IsEqualTo(0); } finally { connection.Execute("drop table #TransactionTest;"); } } public void TestReaderWhenResultsChange() { try { connection.Execute("create table #ResultsChange (X int);create table #ResultsChange2 (Y int);insert #ResultsChange (X) values(1);insert #ResultsChange2 (Y) values(1);"); var obj1 = connection.Query<ResultsChangeType>("select * from #ResultsChange").Single(); obj1.X.IsEqualTo(1); obj1.Y.IsEqualTo(0); obj1.Z.IsEqualTo(0); var obj2 = connection.Query<ResultsChangeType>("select * from #ResultsChange rc inner join #ResultsChange2 rc2 on rc2.Y=rc.X").Single(); obj2.X.IsEqualTo(1); obj2.Y.IsEqualTo(1); obj2.Z.IsEqualTo(0); connection.Execute("alter table #ResultsChange add Z int null"); connection.Execute("update #ResultsChange set Z = 2"); var obj3 = connection.Query<ResultsChangeType>("select * from #ResultsChange").Single(); obj3.X.IsEqualTo(1); obj3.Y.IsEqualTo(0); obj3.Z.IsEqualTo(2); var obj4 = connection.Query<ResultsChangeType>("select * from #ResultsChange rc inner join #ResultsChange2 rc2 on rc2.Y=rc.X").Single(); obj4.X.IsEqualTo(1); obj4.Y.IsEqualTo(1); obj4.Z.IsEqualTo(2); } finally { connection.Execute("drop table #ResultsChange;drop table #ResultsChange2;"); } } class ResultsChangeType { public int X { get; set; } public int Y { get; set; } public int Z { get; set; } } public void TestCustomTypeMap() { // default mapping var item = connection.Query<TypeWithMapping>("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().Where(prop => GetDescriptionFromAttribute(prop) == columnName).FirstOrDefault()); Dapper.SqlMapper.SetTypeMap(typeof(TypeWithMapping), map); item = connection.Query<TypeWithMapping>("Select 'AVal' as A, 'BVal' as B").Single(); item.A.IsEqualTo("BVal"); item.B.IsEqualTo("AVal"); // reset to default Dapper.SqlMapper.SetTypeMap(typeof(TypeWithMapping), null); item = connection.Query<TypeWithMapping>("Select 'AVal' as A, 'BVal' as B").Single(); item.A.IsEqualTo("AVal"); item.B.IsEqualTo("BVal"); } static string GetDescriptionFromAttribute(MemberInfo member) { if (member == null) return null; #if DNXCORE50 var data = member.CustomAttributes.FirstOrDefault(x => x.AttributeType == typeof(DescriptionAttribute)); return data == null ? null : (string)data.ConstructorArguments.Single().Value; #else var attrib = (DescriptionAttribute)Attribute.GetCustomAttribute(member, typeof(DescriptionAttribute), false); return attrib == null ? null : 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; } public double B { get; set; } public long C { get; set; } public bool D { get; set; } } public void TestWrongTypes_WithRightTypes() { var item = connection.Query<WrongTypes>("select 1 as A, cast(2.0 as float) as B, cast(3 as bigint) as C, cast(1 as bit) as D").Single(); item.A.Equals(1); item.B.Equals(2.0); item.C.Equals(3L); item.D.Equals(true); } public void TestWrongTypes_WithWrongTypes() { var item = connection.Query<WrongTypes>("select cast(1.0 as float) as A, 2 as B, 3 as C, cast(1 as bigint) as D").Single(); item.A.Equals(1); item.B.Equals(2.0); item.C.Equals(3L); item.D.Equals(true); } public void Test_AddDynamicParametersRepeatedShouldWork() { var args = new DynamicParameters(); args.AddDynamicParams(new { Foo = 123 }); args.AddDynamicParams(new { Foo = 123 }); int i = connection.Query<int>("select @Foo", args).Single(); i.IsEqualTo(123); } public class ParameterWithIndexer { public int A { get; set; } public virtual string this[string columnName] { get { return null; } set { } } } public void TestParameterWithIndexer() { connection.Execute(@"create proc #TestProcWithIndexer @A int as begin select @A end"); var item = connection.Query<int>("#TestProcWithIndexer", new ParameterWithIndexer(), commandType: CommandType.StoredProcedure).Single(); } public class MultipleParametersWithIndexerDeclaringType { public object this[object field] { get { return null; } set { } } public object this[object field, int index] { get { return null; } set { } } public int B { get; set; } } public class MultipleParametersWithIndexer : MultipleParametersWithIndexerDeclaringType { public int A { get; set; } } public void TestMultipleParametersWithIndexer() { var order = connection.Query<MultipleParametersWithIndexer>("select 1 A,2 B").First(); order.A.IsEqualTo(1); order.B.IsEqualTo(2); } public void Issue_40_AutomaticBoolConversion() { var user = connection.Query<Issue40_User>("select UserId=1,Email='abc',Password='changeme',Active=cast(1 as tinyint)").Single(); user.Active.IsTrue(); user.UserID.IsEqualTo(1); user.Email.IsEqualTo("abc"); user.Password.IsEqualTo("changeme"); } public class Issue40_User { public Issue40_User() { Email = Password = String.Empty; } public int UserID { get; set; } public string Email { get; set; } public string Password { get; set; } public bool Active { get; set; } } SqlConnection GetClosedConnection() { var conn = new SqlConnection(connection.ConnectionString); if (conn.State != ConnectionState.Closed) throw new InvalidOperationException("should be closed!"); return conn; } public void ExecuteFromClosed() { using (var conn = GetClosedConnection()) { conn.Execute("-- nop"); conn.State.IsEqualTo(ConnectionState.Closed); } } class Multi1 { public int Id { get; set; } } class Multi2 { public int Id { get; set; } } public void QueryMultimapFromClosed() { using (var conn = GetClosedConnection()) { conn.State.IsEqualTo(ConnectionState.Closed); var i = conn.Query<Multi1, Multi2, int>("select 2 as [Id], 3 as [Id]", (x, y) => x.Id + y.Id).Single(); conn.State.IsEqualTo(ConnectionState.Closed); i.IsEqualTo(5); } } public void QueryMultiple2FromClosed() { using (var conn = GetClosedConnection()) { conn.State.IsEqualTo(ConnectionState.Closed); using (var multi = conn.QueryMultiple("select 1 select 2 select 3")) { multi.Read<int>().Single().IsEqualTo(1); multi.Read<int>().Single().IsEqualTo(2); // not reading 3 is intentional here } conn.State.IsEqualTo(ConnectionState.Closed); } } public void ExecuteInvalidFromClosed() { using (var conn = GetClosedConnection()) { try { conn.Execute("nop"); false.IsEqualTo(true); // shouldn't have got here } catch { conn.State.IsEqualTo(ConnectionState.Closed); } } } public void QueryFromClosed() { using (var conn = GetClosedConnection()) { var i = conn.Query<int>("select 1").Single(); conn.State.IsEqualTo(ConnectionState.Closed); i.IsEqualTo(1); } } public void QueryInvalidFromClosed() { using (var conn = GetClosedConnection()) { try { conn.Query<int>("select gibberish").Single(); false.IsEqualTo(true); // shouldn't have got here } catch { conn.State.IsEqualTo(ConnectionState.Closed); } } } public void QueryMultipleFromClosed() { using (var conn = GetClosedConnection()) { using (var multi = conn.QueryMultiple("select 1; select 'abc';")) { multi.Read<int>().Single().IsEqualTo(1); multi.Read<string>().Single().IsEqualTo("abc"); } conn.State.IsEqualTo(ConnectionState.Closed); } } public void QueryMultipleInvalidFromClosed() { using (var conn = GetClosedConnection()) { try { conn.QueryMultiple("select gibberish"); false.IsEqualTo(true); // shouldn't have got here } catch { conn.State.IsEqualTo(ConnectionState.Closed); } } } public void TestMultiSelectWithSomeEmptyGrids() { using (var reader = connection.QueryMultiple("select 1; select 2 where 1 = 0; select 3 where 1 = 0; select 4;")) { var one = reader.Read<int>().ToArray(); var two = reader.Read<int>().ToArray(); var three = reader.Read<int>().ToArray(); var four = reader.Read<int>().ToArray(); try { // only returned four grids; expect a fifth read to fail reader.Read<int>(); throw new InvalidOperationException("this should not have worked!"); } catch (ObjectDisposedException ex) { // expected; success ex.Message.IsEqualTo("The reader has been disposed; this can happen after all data has been consumed\r\nObject name: 'Dapper.SqlMapper+GridReader'."); } one.Length.IsEqualTo(1); one[0].IsEqualTo(1); two.Length.IsEqualTo(0); three.Length.IsEqualTo(0); four.Length.IsEqualTo(1); four[0].IsEqualTo(4); } } public void TestDynamicMutation() { var obj = connection.Query("select 1 as [a], 2 as [b], 3 as [c]").Single(); ((int)obj.a).IsEqualTo(1); IDictionary<string, object> dict = obj; Assert.Equals(3, dict.Count); Assert.IsTrue(dict.Remove("a")); Assert.IsFalse(dict.Remove("d")); Assert.Equals(2, dict.Count); dict.Add("d", 4); Assert.Equals(3, dict.Count); Assert.Equals("b,c,d", string.Join(",", dict.Keys.OrderBy(x => x))); Assert.Equals("2,3,4", string.Join(",", dict.OrderBy(x => x.Key).Select(x => x.Value))); Assert.Equals(2, (int)obj.b); Assert.Equals(3, (int)obj.c); Assert.Equals(4, (int)obj.d); try { ((int)obj.a).IsEqualTo(1); throw new InvalidOperationException("should have thrown"); } catch (RuntimeBinderException) { // pass } } public void TestIssue131() { var results = connection.Query<dynamic, int, dynamic>( "SELECT 1 Id, 'Mr' Title, 'John' Surname, 4 AddressCount", (person, addressCount) => { return person; }, splitOn: "AddressCount" ).FirstOrDefault(); var asDict = (IDictionary<string, object>)results; asDict.ContainsKey("Id").IsEqualTo(true); asDict.ContainsKey("Title").IsEqualTo(true); asDict.ContainsKey("Surname").IsEqualTo(true); asDict.ContainsKey("AddressCount").IsEqualTo(false); } // see http://stackoverflow.com/questions/16955357/issue-about-dapper public void TestSplitWithMissingMembers() { var result = connection.Query<Topic, Profile, Topic>( @"select 123 as ID, 'abc' as Title, cast('01 Feb 2013' as datetime) as CreateDate, 'ghi' as Name, 'def' as Phone", (T, P) => { T.Author = P; return T; }, null, null, true, "ID,Name").Single(); result.ID.Equals(123); result.Title.Equals("abc"); result.CreateDate.Equals(new DateTime(2013, 2, 1)); result.Name.IsNull(); result.Content.IsNull(); result.Author.Phone.Equals("def"); result.Author.Name.Equals("ghi"); result.Author.ID.Equals(0); result.Author.Address.IsNull(); } public class Profile { public int ID { get; set; } public string Name { get; set; } public string Phone { get; set; } public string Address { get; set; } //public ExtraInfo Extra { get; set; } } public class Topic { public int ID { get; set; } public string Title { get; set; } public DateTime CreateDate { get; set; } public string Content { get; set; } public int UID { get; set; } public int TestColum { get; set; } public string Name { get; set; } public Profile Author { get; set; } //public Attachment Attach { get; set; } } // see http://stackoverflow.com/questions/13127886/dapper-returns-null-for-singleordefaultdatediff public void TestNullFromInt_NoRows() { var result = connection.Query<int>( // case with rows "select DATEDIFF(day, GETUTCDATE(), @date)", new { date = DateTime.UtcNow.AddDays(20) }) .SingleOrDefault(); result.IsEqualTo(20); result = connection.Query<int>( // case without rows "select DATEDIFF(day, GETUTCDATE(), @date) where 1 = 0", new { date = DateTime.UtcNow.AddDays(20) }) .SingleOrDefault(); result.IsEqualTo(0); // zero rows; default of int over zero rows is zero } public void TestChangingDefaultStringTypeMappingToAnsiString() { var sql = "SELECT SQL_VARIANT_PROPERTY(CONVERT(sql_variant, @testParam),'BaseType') AS BaseType"; var param = new { testParam = "TestString" }; var result01 = connection.Query<string>(sql, param).FirstOrDefault(); result01.IsEqualTo("nvarchar"); Dapper.SqlMapper.PurgeQueryCache(); Dapper.SqlMapper.AddTypeMap(typeof(string), DbType.AnsiString); // Change Default String Handling to AnsiString var result02 = connection.Query<string>(sql, param).FirstOrDefault(); result02.IsEqualTo("varchar"); Dapper.SqlMapper.PurgeQueryCache(); Dapper.SqlMapper.AddTypeMap(typeof(string), DbType.String); // Restore Default to Unicode String } #if DNXCORE50 class TransactedConnection : IDbConnection { IDbConnection _conn; IDbTransaction _tran; public TransactedConnection(IDbConnection conn, IDbTransaction tran) { _conn = conn; _tran = tran; } public override string ConnectionString { get { return _conn.ConnectionString; } set { _conn.ConnectionString = value; } } public override int ConnectionTimeout { get { return _conn.ConnectionTimeout; } } public override string Database { get { return _conn.Database; } } public override ConnectionState State { get { return _conn.State; } } protected override IDbTransaction BeginDbTransaction(IsolationLevel isolationLevel) { return _tran; } public override void ChangeDatabase(string databaseName) { _conn.ChangeDatabase(databaseName); } public override string DataSource { get { return _conn.DataSource; } } public override string ServerVersion { get { return _conn.ServerVersion; } } public override void Close() { _conn.Close(); } protected override IDbCommand CreateDbCommand() { // The command inherits the "current" transaction. var command = _conn.CreateCommand(); command.Transaction = _tran; return command; } protected override void Dispose(bool disposing) { if(disposing) _conn.Dispose(); base.Dispose(disposing); } public override void Open() { _conn.Open(); } } #else class TransactedConnection : IDbConnection { IDbConnection _conn; IDbTransaction _tran; public TransactedConnection(IDbConnection conn, IDbTransaction tran) { _conn = conn; _tran = tran; } public string ConnectionString { get { return _conn.ConnectionString; } set { _conn.ConnectionString = value; } } public int ConnectionTimeout { get { return _conn.ConnectionTimeout; } } public string Database { get { return _conn.Database; } } public ConnectionState State { get { return _conn.State; } } public IDbTransaction BeginTransaction(IsolationLevel il) { throw new NotImplementedException(); } public IDbTransaction BeginTransaction() { return _tran; } public void ChangeDatabase(string databaseName) { _conn.ChangeDatabase(databaseName); } public void Close() { _conn.Close(); } public IDbCommand CreateCommand() { // The command inherits the "current" transaction. var command = _conn.CreateCommand(); command.Transaction = _tran; return command; } public void Dispose() { _conn.Dispose(); } public void Open() { _conn.Open(); } } #endif public void TestDapperTableMetadataRetrieval() { // Test for a bug found in CS 51509960 where the following sequence would result in an InvalidOperationException being // thrown due to an attempt to access a disposed of DataReader: // // - Perform a dynamic query that yields no results // - Add data to the source of that query // - Perform a the same query again connection.Execute("CREATE TABLE #sut (value varchar(10) NOT NULL PRIMARY KEY)"); connection.Query("SELECT value FROM #sut").IsSequenceEqualTo(Enumerable.Empty<dynamic>()); connection.Execute("INSERT INTO #sut (value) VALUES ('test')").IsEqualTo(1); var result = connection.Query("SELECT value FROM #sut"); var first = result.First(); ((string)first.value).IsEqualTo("test"); } public void TestIssue17648290() { var p = new DynamicParameters(); int code = 1, getMessageControlId = 2; p.Add("@Code", code); p.Add("@MessageControlID", getMessageControlId); p.Add("@SuccessCode", dbType: DbType.Int32, direction: ParameterDirection.Output); p.Add("@ErrorDescription", dbType: DbType.String, direction: ParameterDirection.Output, size: 255); connection.Execute(@"CREATE PROCEDURE #up_MessageProcessed_get @Code varchar(10), @MessageControlID varchar(22), @SuccessCode int OUTPUT, @ErrorDescription varchar(255) OUTPUT AS BEGIN Select 2 as MessageProcessID, 38349348 as StartNum, 3874900 as EndNum, GETDATE() as StartDate, GETDATE() as EndDate SET @SuccessCode = 0 SET @ErrorDescription = 'Completed successfully' END"); var result = connection.Query(sql: "#up_MessageProcessed_get", param: p, commandType: CommandType.StoredProcedure); var row = result.Single(); ((int)row.MessageProcessID).IsEqualTo(2); ((int)row.StartNum).IsEqualTo(38349348); ((int)row.EndNum).IsEqualTo(3874900); DateTime startDate = row.StartDate, endDate = row.EndDate; p.Get<int>("SuccessCode").IsEqualTo(0); p.Get<string>("ErrorDescription").IsEqualTo("Completed successfully"); } public void TestDoubleDecimalConversions_SO18228523_RightWay() { var row = connection.Query<HasDoubleDecimal>( "select cast(1 as float) as A, cast(2 as float) as B, cast(3 as decimal) as C, cast(4 as decimal) as D").Single(); row.A.Equals(1.0); row.B.Equals(2.0); row.C.Equals(3.0M); row.D.Equals(4.0M); } public void TestDoubleDecimalConversions_SO18228523_WrongWay() { var row = connection.Query<HasDoubleDecimal>( "select cast(1 as decimal) as A, cast(2 as decimal) as B, cast(3 as float) as C, cast(4 as float) as D").Single(); row.A.Equals(1.0); row.B.Equals(2.0); row.C.Equals(3.0M); row.D.Equals(4.0M); } public void TestDoubleDecimalConversions_SO18228523_Nulls() { var row = connection.Query<HasDoubleDecimal>( "select cast(null as decimal) as A, cast(null as decimal) as B, cast(null as float) as C, cast(null as float) as D").Single(); row.A.Equals(0.0); row.B.IsNull(); row.C.Equals(0.0M); row.D.IsNull(); } private static CultureInfo ActiveCulture { #if DNXCORE50 get { return CultureInfo.CurrentCulture; } set { CultureInfo.CurrentCulture = value; } #else get { return Thread.CurrentThread.CurrentCulture; } set { Thread.CurrentThread.CurrentCulture = value; } #endif } public void TestParameterInclusionNotSensitiveToCurrentCulture() { // note this might fail if your database server is case-sensitive CultureInfo current = ActiveCulture; try { ActiveCulture = new CultureInfo("tr-TR"); connection.Query<int>("select @pid", new { PId = 1 }).Single(); } finally { ActiveCulture = current; } } public void LiteralReplacement() { connection.Execute("create table #literal1 (id int not null, foo int not null)"); connection.Execute("insert #literal1 (id,foo) values ({=id}, @foo)", new { id = 123, foo = 456 }); var rows = new[] { new { id = 1, foo = 2 }, new { id = 3, foo = 4 } }; connection.Execute("insert #literal1 (id,foo) values ({=id}, @foo)", rows); var count = connection.Query<int>("select count(1) from #literal1 where id={=foo}", new { foo = 123 }).Single(); count.IsEqualTo(1); int sum = connection.Query<int>("select sum(id) + sum(foo) from #literal1").Single(); sum.IsEqualTo(123 + 456 + 1 + 2 + 3 + 4); } public void LiteralReplacementDynamic() { var args = new DynamicParameters(); args.Add("id", 123); connection.Execute("create table #literal2 (id int not null)"); connection.Execute("insert #literal2 (id) values ({=id})", args); args = new DynamicParameters(); args.Add("foo", 123); var count = connection.Query<int>("select count(1) from #literal2 where id={=foo}", args).Single(); count.IsEqualTo(1); } enum AnEnum { A = 2, B = 1 } enum AnotherEnum : byte { A = 2, B = 1 } #if DNXCORE50 [FrameworkFail("https://github.com/dotnet/corefx/issues/1613")] #endif public void AdoNetEnumValue() { using (var cmd = connection.CreateCommand()) { cmd.CommandText = "select @foo"; cmd.Parameters.AddWithValue("@foo", AnEnum.B); object value = cmd.ExecuteScalar(); AnEnum val = (AnEnum)value; val.IsEqualTo(AnEnum.B); } } public void LiteralReplacementEnumAndString() { var args = new { x = AnEnum.B, y = 123.45M, z = AnotherEnum.A }; var row = connection.Query("select {=x} as x,{=y} as y,cast({=z} as tinyint) as z", args).Single(); AnEnum x = (AnEnum)(int)row.x; decimal y = row.y; AnotherEnum z = (AnotherEnum)(byte)row.z; x.Equals(AnEnum.B); y.Equals(123.45M); z.Equals(AnotherEnum.A); } public void LiteralReplacementDynamicEnumAndString() { var args = new DynamicParameters(); args.Add("x", AnEnum.B); args.Add("y", 123.45M); args.Add("z", AnotherEnum.A); var row = connection.Query("select {=x} as x,{=y} as y,cast({=z} as tinyint) as z", args).Single(); AnEnum x = (AnEnum)(int)row.x; decimal y = row.y; AnotherEnum z = (AnotherEnum)(byte)row.z; x.Equals(AnEnum.B); y.Equals(123.45M); z.Equals(AnotherEnum.A); } public void LiteralReplacementBoolean() { var row = connection.Query<int?>("select 42 where 1 = {=val}", new { val = true }).SingleOrDefault(); row.IsNotNull(); row.IsEqualTo(42); row = connection.Query<int?>("select 42 where 1 = {=val}", new { val = false }).SingleOrDefault(); row.IsNull(); } public void LiteralReplacementWithIn() { var data = connection.Query<MyRow>("select @x where 1 in @ids and 1 ={=a}", new { x = 1, ids = new[] { 1, 2, 3 }, a = 1 }).ToList(); } class MyRow { public int x { get; set; } } public void LiteralIn() { connection.Execute("create table #literalin(id int not null);"); connection.Execute("insert #literalin (id) values (@id)", new[] { new { id = 1 }, new { id = 2 }, new { id = 3 }, }); var count = connection.Query<int>("select count(1) from #literalin where id in {=ids}", new { ids = new[] { 1, 3, 4 } }).Single(); count.IsEqualTo(2); } public void ParameterizedInWithOptimizeHint() { const string sql = @" select count(1) from( select 1 as x union all select 2 union all select 5) y where y.x in @vals option (optimize for (@vals unKnoWn))"; int count = connection.Query<int>(sql, new { vals = new[] { 1, 2, 3, 4 } }).Single(); count.IsEqualTo(2); count = connection.Query<int>(sql, new { vals = new[] { 1 } }).Single(); count.IsEqualTo(1); count = connection.Query<int>(sql, new { vals = new int[0] }).Single(); count.IsEqualTo(0); } public void TestProcedureWithTimeParameter() { var p = new DynamicParameters(); p.Add("a", TimeSpan.FromHours(10), dbType: DbType.Time); connection.Execute(@"CREATE PROCEDURE #TestProcWithTimeParameter @a TIME AS BEGIN SELECT @a END"); connection.Query<TimeSpan>("#TestProcWithTimeParameter", p, commandType: CommandType.StoredProcedure).First().IsEqualTo(new TimeSpan(10, 0, 0)); } public void DbString() { var a = connection.Query<int>("select datalength(@x)", new { x = new DbString { Value = "abc", IsAnsi = true } }).Single(); var b = connection.Query<int>("select datalength(@x)", new { x = new DbString { Value = "abc", IsAnsi = false } }).Single(); a.IsEqualTo(3); b.IsEqualTo(6); } class HasInt32 { public int Value { get; set; } } // http://stackoverflow.com/q/23696254/23354 public void DownwardIntegerConversion() { const string sql = "select cast(42 as bigint) as Value"; int i = connection.Query<HasInt32>(sql).Single().Value; Assert.IsEqualTo(42, i); i = connection.Query<int>(sql).Single(); Assert.IsEqualTo(42, i); } class HasDoubleDecimal { public double A { get; set; } public double? B { get; set; } public decimal C { get; set; } public decimal? D { get; set; } } #if EXTERNALS public void DataTableParameters() { try { connection.Execute("drop proc #DataTableParameters"); } catch { } try { connection.Execute("drop table #DataTableParameters"); } catch { } try { connection.Execute("drop type MyTVPType"); } catch { } connection.Execute("create type MyTVPType as table (id int)"); connection.Execute("create proc #DataTableParameters @ids MyTVPType readonly as select count(1) from @ids"); var table = new DataTable { Columns = { { "id", typeof(int) } }, Rows = { { 1 }, { 2 }, { 3 } } }; int count = connection.Query<int>("#DataTableParameters", new { ids = table.AsTableValuedParameter() }, commandType: CommandType.StoredProcedure).First(); count.IsEqualTo(3); count = connection.Query<int>("select count(1) from @ids", new { ids = table.AsTableValuedParameter("MyTVPType") }).First(); count.IsEqualTo(3); try { connection.Query<int>("select count(1) from @ids", new { ids = table.AsTableValuedParameter() }).First(); throw new InvalidOperationException(); } catch (Exception ex) { ex.Message.Equals("The table type parameter 'ids' must have a valid type name."); } } public void SO29533765_DataTableParametersViaDynamicParameters() { try { connection.Execute("drop proc #DataTableParameters"); } catch { } try { connection.Execute("drop table #DataTableParameters"); } catch { } try { connection.Execute("drop type MyTVPType"); } catch { } connection.Execute("create type MyTVPType as table (id int)"); connection.Execute("create proc #DataTableParameters @ids MyTVPType readonly as select count(1) from @ids"); var table = new DataTable { TableName="MyTVPType", Columns = { { "id", typeof(int) } }, Rows = { { 1 }, { 2 }, { 3 } } }; table.SetTypeName(table.TableName); // per SO29533765 IDictionary<string, object> args = new Dictionary<string, object>(); args.Add("ids", table); int count = connection.Query<int>("#DataTableParameters", args, commandType: CommandType.StoredProcedure).First(); count.IsEqualTo(3); count = connection.Query<int>("select count(1) from @ids", args).First(); count.IsEqualTo(3); } public void SO26468710_InWithTVPs() { // this is just to make it re-runnable; normally you only do this once try { connection.Execute("drop type MyIdList"); } catch { } connection.Execute("create type MyIdList as table(id int);"); DataTable ids = new DataTable { Columns = { { "id", typeof(int) } }, Rows = { { 1 }, { 3 }, { 5 } } }; ids.SetTypeName("MyIdList"); int sum = connection.Query<int>(@" declare @tmp table(id int not null); insert @tmp (id) values(1), (2), (3), (4), (5), (6), (7); select * from @tmp t inner join @ids i on i.id = t.id", new { ids }).Sum(); sum.IsEqualTo(9); } public void DataTableParametersWithExtendedProperty() { try { connection.Execute("drop proc #DataTableParameters"); } catch { } try { connection.Execute("drop table #DataTableParameters"); } catch { } try { connection.Execute("drop type MyTVPType"); } catch { } connection.Execute("create type MyTVPType as table (id int)"); connection.Execute("create proc #DataTableParameters @ids MyTVPType readonly as select count(1) from @ids"); var table = new DataTable { Columns = { { "id", typeof(int) } }, Rows = { { 1 }, { 2 }, { 3 } } }; table.SetTypeName("MyTVPType"); // <== extended metadata int count = connection.Query<int>("#DataTableParameters", new { ids = table }, commandType: CommandType.StoredProcedure).First(); count.IsEqualTo(3); count = connection.Query<int>("select count(1) from @ids", new { ids = table }).First(); count.IsEqualTo(3); try { connection.Query<int>("select count(1) from @ids", new { ids = table }).First(); throw new InvalidOperationException(); } catch (Exception ex) { ex.Message.Equals("The table type parameter 'ids' must have a valid type name."); } } public void SupportInit() { var obj = connection.Query<WithInit>("select 'abc' as Value").Single(); obj.Value.Equals("abc"); obj.Flags.Equals(31); } #endif public void GuidIn_SO_24177902() { // invent and populate Guid a = Guid.NewGuid(), b = Guid.NewGuid(), c = Guid.NewGuid(), d = Guid.NewGuid(); connection.Execute("create table #foo (i int, g uniqueidentifier)"); connection.Execute("insert #foo(i,g) values(@i,@g)", new[] { new { i = 1, g = a }, new { i = 2, g = b }, new { i = 3, g = c },new { i = 4, g = d }}); // check that rows 2&3 yield guids b&c var guids = connection.Query<Guid>("select g from #foo where i in (2,3)").ToArray(); guids.Length.Equals(2); guids.Contains(a).Equals(false); guids.Contains(b).Equals(true); guids.Contains(c).Equals(true); guids.Contains(d).Equals(false); // in query on the guids var rows = connection.Query("select * from #foo where g in @guids order by i", new { guids }) .Select(row => new { i = (int)row.i, g = (Guid)row.g }).ToArray(); rows.Length.Equals(2); rows[0].i.Equals(2); rows[0].g.Equals(b); rows[1].i.Equals(3); rows[1].g.Equals(c); } #if EXTERNALS class HazGeo { public int Id { get; set; } public DbGeography Geo { get; set; } public DbGeometry Geometry { get; set; } } class HazSqlGeo { public int Id { get; set; } public SqlGeography Geo { get; set; } public SqlGeometry Geometry { get; set; } } public void DBGeography_SO24405645_SO24402424() { Dapper.EntityFramework.Handlers.Register(); connection.Execute("create table #Geo (id int, geo geography, geometry geometry)"); var obj = new HazGeo { Id = 1, Geo = DbGeography.LineFromText("LINESTRING(-122.360 47.656, -122.343 47.656 )", 4326), Geometry = DbGeometry.LineFromText("LINESTRING (100 100, 20 180, 180 180)", 0) }; connection.Execute("insert #Geo(id, geo, geometry) values (@Id, @Geo, @Geometry)", obj); var row = connection.Query<HazGeo>("select * from #Geo where id=1").SingleOrDefault(); row.IsNotNull(); row.Id.IsEqualTo(1); row.Geo.IsNotNull(); row.Geometry.IsNotNull(); } public void SqlGeography_SO25538154() { Dapper.SqlMapper.ResetTypeHandlers(); connection.Execute("create table #SqlGeo (id int, geo geography, geometry geometry)"); var obj = new HazSqlGeo { Id = 1, Geo = SqlGeography.STLineFromText(new SqlChars(new SqlString("LINESTRING(-122.360 47.656, -122.343 47.656 )")), 4326), Geometry = SqlGeometry.STLineFromText(new SqlChars(new SqlString("LINESTRING (100 100, 20 180, 180 180)")), 0) }; connection.Execute("insert #SqlGeo(id, geo, geometry) values (@Id, @Geo, @Geometry)", obj); var row = connection.Query<HazSqlGeo>("select * from #SqlGeo where id=1").SingleOrDefault(); row.IsNotNull(); row.Id.IsEqualTo(1); row.Geo.IsNotNull(); row.Geometry.IsNotNull(); } public void SqlHierarchyId_SO18888911() { Dapper.SqlMapper.ResetTypeHandlers(); var row = connection.Query<HazSqlHierarchy>("select 3 as [Id], hierarchyid::Parse('/1/2/3/') as [Path]").Single(); row.Id.Equals(3); row.Path.IsNotNull(); var val = connection.Query<SqlHierarchyId>("select @Path", row).Single(); val.IsNotNull(); } public class HazSqlHierarchy { public int Id { get; set; } public SqlHierarchyId Path { get; set; } } #endif public void TypeBasedViaDynamic() { Type type = GetSomeType(); dynamic template = Activator.CreateInstance(type); dynamic actual = CheetViaDynamic(template, "select @A as [A], @B as [B]", new { A = 123, B = "abc" }); ((object)actual).GetType().IsEqualTo(type); int a = actual.A; string b = actual.B; a.IsEqualTo(123); b.IsEqualTo("abc"); } public void TypeBasedViaType() { Type type = GetSomeType(); dynamic actual = connection.Query(type, "select @A as [A], @B as [B]", new { A = 123, B = "abc" }).FirstOrDefault(); ((object)actual).GetType().IsEqualTo(type); int a = actual.A; string b = actual.B; a.IsEqualTo(123); b.IsEqualTo("abc"); } public void TypeBasedViaTypeMulti() { Type type = GetSomeType(); dynamic first, second; using (var multi = connection.QueryMultiple("select @A as [A], @B as [B]; select @C as [A], @D as [B]", new { A = 123, B = "abc", C = 456, D = "def" })) { first = multi.Read(type).Single(); second = multi.Read(type).Single(); } ((object)first).GetType().IsEqualTo(type); int a = first.A; string b = first.B; a.IsEqualTo(123); b.IsEqualTo("abc"); ((object)second).GetType().IsEqualTo(type); a = second.A; b = second.B; a.IsEqualTo(456); b.IsEqualTo("def"); } T CheetViaDynamic<T>(T template, string query, object args) { return connection.Query<T>(query, args).SingleOrDefault(); } static Type GetSomeType() { return typeof(SomeType); } public class SomeType { public int A { get; set; } public string B { get; set; } } #if !DNXCORE50 class WithInit : ISupportInitialize { public string Value { get; set; } public int Flags { get; set; } void ISupportInitialize.BeginInit() { Flags += 1; } void ISupportInitialize.EndInit() { Flags += 30; } } #endif public void SO24607639_NullableBools() { var obj = connection.Query<HazBools>( @"declare @vals table (A bit null, B bit null, C bit null); insert @vals (A,B,C) values (1,0,null); select * from @vals").Single(); obj.IsNotNull(); obj.A.Value.IsEqualTo(true); obj.B.Value.IsEqualTo(false); obj.C.IsNull(); } class HazBools { public bool? A { get; set; } public bool? B { get; set; } public bool? C { get; set; } } public void SO24605346_ProcsAndStrings() { connection.Execute(@"create proc #GetPracticeRebateOrderByInvoiceNumber @TaxInvoiceNumber nvarchar(20) as select @TaxInvoiceNumber as [fTaxInvoiceNumber]"); string InvoiceNumber = "INV0000000028PPN"; var result = connection.Query<PracticeRebateOrders>("#GetPracticeRebateOrderByInvoiceNumber", new { TaxInvoiceNumber = InvoiceNumber }, commandType: CommandType.StoredProcedure).FirstOrDefault(); result.TaxInvoiceNumber.IsEqualTo("INV0000000028PPN"); } class PracticeRebateOrders { public string fTaxInvoiceNumber; #if EXTERNALS [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] #endif public string TaxInvoiceNumber { get { return fTaxInvoiceNumber; } set { fTaxInvoiceNumber = value; } } } public class RatingValueHandler : Dapper.SqlMapper.TypeHandler<RatingValue> { private RatingValueHandler() { } public static readonly RatingValueHandler Default = new RatingValueHandler(); public override RatingValue Parse(object value) { if (value is Int32) return new RatingValue() { Value = (Int32)value }; throw new FormatException("Invalid conversion to RatingValue"); } public override void SetValue(IDbDataParameter parameter, RatingValue value) { // ... null, range checks etc ... parameter.DbType = System.Data.DbType.Int32; parameter.Value = value.Value; } } public class RatingValue { public Int32 Value { get; set; } // ... some other properties etc ... } public class MyResult { public String CategoryName { get; set; } public RatingValue CategoryRating { get; set; } } public void SO24740733_TestCustomValueHandler() { Dapper.SqlMapper.AddTypeHandler(RatingValueHandler.Default); var foo = connection.Query<MyResult>("SELECT 'Foo' AS CategoryName, 200 AS CategoryRating").Single(); foo.CategoryName.IsEqualTo("Foo"); foo.CategoryRating.Value.IsEqualTo(200); } enum SO27024806Enum { Foo, Bar } private class SO27024806Class { public SO27024806Class(SO27024806Enum myField) { this.MyField = myField; } public SO27024806Enum MyField { get; set; } } public void SO27024806_TestVarcharEnumMemberWithExplicitConstructor() { var foo = connection.Query<SO27024806Class>("SELECT 'Foo' AS myField").Single(); foo.MyField.IsEqualTo(SO27024806Enum.Foo); } public void SO24740733_TestCustomValueSingleColumn() { Dapper.SqlMapper.AddTypeHandler(RatingValueHandler.Default); var foo = connection.Query<RatingValue>("SELECT 200 AS CategoryRating").Single(); foo.Value.IsEqualTo(200); } public void Issue130_IConvertible() { dynamic row = connection.Query("select 1 as [a], '2' as [b]").Single(); int a = row.a; string b = row.b; a.IsEqualTo(1); b.IsEqualTo("2"); row = connection.Query<dynamic>("select 3 as [a], '4' as [b]").Single(); a = row.a; b = row.b; a.IsEqualTo(3); b.IsEqualTo("4"); } public void Issue22_ExecuteScalar() { int i = connection.ExecuteScalar<int>("select 123"); i.IsEqualTo(123); i = connection.ExecuteScalar<int>("select cast(123 as bigint)"); i.IsEqualTo(123); long j = connection.ExecuteScalar<long>("select 123"); j.IsEqualTo(123L); j = connection.ExecuteScalar<long>("select cast(123 as bigint)"); j.IsEqualTo(123L); int? k = connection.ExecuteScalar<int?>("select @i", new { i = default(int?) }); k.IsNull(); #if EXTERNALS Dapper.EntityFramework.Handlers.Register(); var geo = DbGeography.LineFromText("LINESTRING(-122.360 47.656, -122.343 47.656 )", 4326); var geo2 = connection.ExecuteScalar<DbGeography>("select @geo", new { geo }); geo2.IsNotNull(); #endif } public void Issue142_FailsNamedStatus() { var row1 = connection.Query<Issue142_Status>("select @Status as [Status]", new { Status = StatusType.Started }).Single(); row1.Status.IsEqualTo(StatusType.Started); var row2 = connection.Query<Issue142_StatusType>("select @Status as [Status]", new { Status = Status.Started }).Single(); row2.Status.IsEqualTo(Status.Started); } public class Issue142_Status { public StatusType Status { get; set; } } public class Issue142_StatusType { public Status Status { get; set; } } public enum StatusType : byte { NotStarted = 1, Started = 2, Finished = 3 } public enum Status : byte { NotStarted = 1, Started = 2, Finished = 3 } public void Issue136_ValueTypeHandlers() { Dapper.SqlMapper.ResetTypeHandlers(); Dapper.SqlMapper.AddTypeHandler(typeof(LocalDate), LocalDateHandler.Default); var param = new LocalDateResult { NotNullable = new LocalDate { Year = 2014, Month = 7, Day = 25 }, NullableNotNull = new LocalDate { Year = 2014, Month = 7, Day = 26 }, NullableIsNull = null, }; var result = connection.Query<LocalDateResult>("SELECT @NotNullable AS NotNullable, @NullableNotNull AS NullableNotNull, @NullableIsNull AS NullableIsNull", param).Single(); Dapper.SqlMapper.ResetTypeHandlers(); Dapper.SqlMapper.AddTypeHandler(typeof(LocalDate?), LocalDateHandler.Default); result = connection.Query<LocalDateResult>("SELECT @NotNullable AS NotNullable, @NullableNotNull AS NullableNotNull, @NullableIsNull AS NullableIsNull", param).Single(); } public class LocalDateHandler : Dapper.SqlMapper.TypeHandler<LocalDate> { private LocalDateHandler() { } // Make the field type ITypeHandler to ensure it cannot be used with SqlMapper.AddTypeHandler<T>(TypeHandler<T>) // by mistake. public static readonly Dapper.SqlMapper.ITypeHandler Default = new LocalDateHandler(); public override LocalDate Parse(object value) { var date = (DateTime)value; return new LocalDate { Year = date.Year, Month = date.Month, Day = date.Day }; } public override void SetValue(IDbDataParameter parameter, LocalDate value) { parameter.DbType = DbType.DateTime; parameter.Value = new DateTime(value.Year, value.Month, value.Day); } } public struct LocalDate { public int Year { get; set; } public int Month { get; set; } public int Day { get; set; } } public class LocalDateResult { public LocalDate NotNullable { get; set; } public LocalDate? NullableNotNull { get; set; } public LocalDate? NullableIsNull { get; set; } } public class LotsOfNumerics { public enum E_Byte : byte { A = 0, B = 1 } public enum E_SByte : sbyte { A = 0, B = 1 } public enum E_Short : short { A = 0, B = 1 } public enum E_UShort : ushort { A = 0, B = 1 } public enum E_Int : int { A = 0, B = 1 } public enum E_UInt : uint { A = 0, B = 1 } public enum E_Long : long { A = 0, B = 1 } public enum E_ULong : ulong { A = 0, B = 1 } public E_Byte P_Byte { get; set; } public E_SByte P_SByte { get; set; } public E_Short P_Short { get; set; } public E_UShort P_UShort { get; set; } public E_Int P_Int { get; set; } public E_UInt P_UInt { get; set; } public E_Long P_Long { get; set; } public E_ULong P_ULong { get; set; } public bool N_Bool { get; set; } public byte N_Byte { get; set; } public sbyte N_SByte { get; set; } public short N_Short { get; set; } public ushort N_UShort { get; set; } public int N_Int { get; set; } public uint N_UInt { get; set; } public long N_Long { get; set; } public ulong N_ULong { get; set; } public float N_Float { get; set; } public double N_Double { get; set; } public decimal N_Decimal { get; set; } public E_Byte? N_P_Byte { get; set; } public E_SByte? N_P_SByte { get; set; } public E_Short? N_P_Short { get; set; } public E_UShort? N_P_UShort { get; set; } public E_Int? N_P_Int { get; set; } public E_UInt? N_P_UInt { get; set; } public E_Long? N_P_Long { get; set; } public E_ULong? N_P_ULong { get; set; } public bool? N_N_Bool { get; set; } public byte? N_N_Byte { get; set; } public sbyte? N_N_SByte { get; set; } public short? N_N_Short { get; set; } public ushort? N_N_UShort { get; set; } public int? N_N_Int { get; set; } public uint? N_N_UInt { get; set; } public long? N_N_Long { get; set; } public ulong? N_N_ULong { get; set; } public float? N_N_Float { get; set; } public double? N_N_Double { get; set; } public decimal? N_N_Decimal { get; set; } } public void TestBigIntForEverythingWorks_SqlLite() { TestBigIntForEverythingWorks_SqlLite_ByDataType<long>("bigint"); TestBigIntForEverythingWorks_SqlLite_ByDataType<int>("int"); TestBigIntForEverythingWorks_SqlLite_ByDataType<byte>("tinyint"); TestBigIntForEverythingWorks_SqlLite_ByDataType<short>("smallint"); TestBigIntForEverythingWorks_SqlLite_ByDataType<bool>("bit"); TestBigIntForEverythingWorks_SqlLite_ByDataType<float>("float(24)"); TestBigIntForEverythingWorks_SqlLite_ByDataType<double>("float(53)"); } private void TestBigIntForEverythingWorks_SqlLite_ByDataType<T>(string dbType) { using (var reader = connection.ExecuteReader("select cast(1 as " + dbType + ")")) { reader.Read().IsTrue(); reader.GetFieldType(0).Equals(typeof(T)); reader.Read().IsFalse(); reader.NextResult().IsFalse(); } string sql = "select " + string.Join(",", typeof(LotsOfNumerics).GetProperties().Select( x => "cast (1 as " + dbType + ") as [" + x.Name + "]")); var row = connection.Query<LotsOfNumerics>(sql).Single(); row.N_Bool.IsTrue(); row.N_SByte.IsEqualTo((sbyte)1); row.N_Byte.IsEqualTo((byte)1); row.N_Int.IsEqualTo((int)1); row.N_UInt.IsEqualTo((uint)1); row.N_Short.IsEqualTo((short)1); row.N_UShort.IsEqualTo((ushort)1); row.N_Long.IsEqualTo((long)1); row.N_ULong.IsEqualTo((ulong)1); row.N_Float.IsEqualTo((float)1); row.N_Double.IsEqualTo((double)1); row.N_Decimal.IsEqualTo((decimal)1); row.P_Byte.IsEqualTo(LotsOfNumerics.E_Byte.B); row.P_SByte.IsEqualTo(LotsOfNumerics.E_SByte.B); row.P_Short.IsEqualTo(LotsOfNumerics.E_Short.B); row.P_UShort.IsEqualTo(LotsOfNumerics.E_UShort.B); row.P_Int.IsEqualTo(LotsOfNumerics.E_Int.B); row.P_UInt.IsEqualTo(LotsOfNumerics.E_UInt.B); row.P_Long.IsEqualTo(LotsOfNumerics.E_Long.B); row.P_ULong.IsEqualTo(LotsOfNumerics.E_ULong.B); row.N_N_Bool.Value.IsTrue(); row.N_N_SByte.Value.IsEqualTo((sbyte)1); row.N_N_Byte.Value.IsEqualTo((byte)1); row.N_N_Int.Value.IsEqualTo((int)1); row.N_N_UInt.Value.IsEqualTo((uint)1); row.N_N_Short.Value.IsEqualTo((short)1); row.N_N_UShort.Value.IsEqualTo((ushort)1); row.N_N_Long.Value.IsEqualTo((long)1); row.N_N_ULong.Value.IsEqualTo((ulong)1); row.N_N_Float.Value.IsEqualTo((float)1); row.N_N_Double.Value.IsEqualTo((double)1); row.N_N_Decimal.IsEqualTo((decimal)1); row.N_P_Byte.Value.IsEqualTo(LotsOfNumerics.E_Byte.B); row.N_P_SByte.Value.IsEqualTo(LotsOfNumerics.E_SByte.B); row.N_P_Short.Value.IsEqualTo(LotsOfNumerics.E_Short.B); row.N_P_UShort.Value.IsEqualTo(LotsOfNumerics.E_UShort.B); row.N_P_Int.Value.IsEqualTo(LotsOfNumerics.E_Int.B); row.N_P_UInt.Value.IsEqualTo(LotsOfNumerics.E_UInt.B); row.N_P_Long.Value.IsEqualTo(LotsOfNumerics.E_Long.B); row.N_P_ULong.Value.IsEqualTo(LotsOfNumerics.E_ULong.B); TestBigIntForEverythingWorks<bool>(true, dbType); TestBigIntForEverythingWorks<sbyte>((sbyte)1, dbType); TestBigIntForEverythingWorks<byte>((byte)1, dbType); TestBigIntForEverythingWorks<int>((int)1, dbType); TestBigIntForEverythingWorks<uint>((uint)1, dbType); TestBigIntForEverythingWorks<short>((short)1, dbType); TestBigIntForEverythingWorks<ushort>((ushort)1, dbType); TestBigIntForEverythingWorks<long>((long)1, dbType); TestBigIntForEverythingWorks<ulong>((ulong)1, dbType); TestBigIntForEverythingWorks<float>((float)1, dbType); TestBigIntForEverythingWorks<double>((double)1, dbType); TestBigIntForEverythingWorks<decimal>((decimal)1, dbType); TestBigIntForEverythingWorks(LotsOfNumerics.E_Byte.B, dbType); TestBigIntForEverythingWorks(LotsOfNumerics.E_SByte.B, dbType); TestBigIntForEverythingWorks(LotsOfNumerics.E_Int.B, dbType); TestBigIntForEverythingWorks(LotsOfNumerics.E_UInt.B, dbType); TestBigIntForEverythingWorks(LotsOfNumerics.E_Short.B, dbType); TestBigIntForEverythingWorks(LotsOfNumerics.E_UShort.B, dbType); TestBigIntForEverythingWorks(LotsOfNumerics.E_Long.B, dbType); TestBigIntForEverythingWorks(LotsOfNumerics.E_ULong.B, dbType); TestBigIntForEverythingWorks<bool?>(true, dbType); TestBigIntForEverythingWorks<sbyte?>((sbyte)1, dbType); TestBigIntForEverythingWorks<byte?>((byte)1, dbType); TestBigIntForEverythingWorks<int?>((int)1, dbType); TestBigIntForEverythingWorks<uint?>((uint)1, dbType); TestBigIntForEverythingWorks<short?>((short)1, dbType); TestBigIntForEverythingWorks<ushort?>((ushort)1, dbType); TestBigIntForEverythingWorks<long?>((long)1, dbType); TestBigIntForEverythingWorks<ulong?>((ulong)1, dbType); TestBigIntForEverythingWorks<float?>((float)1, dbType); TestBigIntForEverythingWorks<double?>((double)1, dbType); TestBigIntForEverythingWorks<decimal?>((decimal)1, dbType); TestBigIntForEverythingWorks<LotsOfNumerics.E_Byte?>(LotsOfNumerics.E_Byte.B, dbType); TestBigIntForEverythingWorks<LotsOfNumerics.E_SByte?>(LotsOfNumerics.E_SByte.B, dbType); TestBigIntForEverythingWorks<LotsOfNumerics.E_Int?>(LotsOfNumerics.E_Int.B, dbType); TestBigIntForEverythingWorks<LotsOfNumerics.E_UInt?>(LotsOfNumerics.E_UInt.B, dbType); TestBigIntForEverythingWorks<LotsOfNumerics.E_Short?>(LotsOfNumerics.E_Short.B, dbType); TestBigIntForEverythingWorks<LotsOfNumerics.E_UShort?>(LotsOfNumerics.E_UShort.B, dbType); TestBigIntForEverythingWorks<LotsOfNumerics.E_Long?>(LotsOfNumerics.E_Long.B, dbType); TestBigIntForEverythingWorks<LotsOfNumerics.E_ULong?>(LotsOfNumerics.E_ULong.B, dbType); } private void TestBigIntForEverythingWorks<T>(T expected, string dbType) { var query = connection.Query<T>("select cast(1 as " + dbType + ")").Single(); query.IsEqualTo(expected); var scalar = connection.ExecuteScalar<T>("select cast(1 as " + dbType + ")"); scalar.IsEqualTo(expected); } public void TestSubsequentQueriesSuccess() { var data0 = connection.Query<Fooz0>("select 1 as [Id] where 1 = 0").ToList(); data0.Count().IsEqualTo(0); var data1 = connection.Query<Fooz1>(new CommandDefinition("select 1 as [Id] where 1 = 0", flags: CommandFlags.Buffered)).ToList(); data1.Count().IsEqualTo(0); var data2 = connection.Query<Fooz2>(new CommandDefinition("select 1 as [Id] where 1 = 0", flags: CommandFlags.None)).ToList(); data2.Count().IsEqualTo(0); data0 = connection.Query<Fooz0>("select 1 as [Id] where 1 = 0").ToList(); data0.Count().IsEqualTo(0); data1 = connection.Query<Fooz1>(new CommandDefinition("select 1 as [Id] where 1 = 0", flags: CommandFlags.Buffered)).ToList(); data1.Count().IsEqualTo(0); data2 = connection.Query<Fooz2>(new CommandDefinition("select 1 as [Id] where 1 = 0", flags: CommandFlags.None)).ToList(); data2.Count().IsEqualTo(0); } class Fooz0 { public int Id { get; set; } } class Fooz1 { public int Id { get; set; } } class Fooz2 { public int Id { get; set; } } public void SO25069578_DynamicParams_Procs() { var parameters = new DynamicParameters(); parameters.Add("foo", "bar"); // parameters = new DynamicParameters(parameters); try { connection.Execute("drop proc SO25069578"); } catch { } connection.Execute("create proc SO25069578 @foo nvarchar(max) as select @foo as [X]"); var tran = connection.BeginTransaction(); // gist used transaction; behaves the same either way, though var row = connection.Query<HazX>("SO25069578", parameters, commandType: CommandType.StoredProcedure, transaction: tran).Single(); tran.Rollback(); row.X.IsEqualTo("bar"); } public void Issue149_TypeMismatch_SequentialAccess() { string error; Guid guid = Guid.Parse("cf0ef7ac-b6fe-4e24-aeda-a2b45bb5654e"); try { var result = connection.Query<Issue149_Person>(@"select @guid as Id", new { guid }).First(); error = null; } catch (Exception ex) { error = ex.Message; } error.IsEqualTo("Error parsing column 0 (Id=cf0ef7ac-b6fe-4e24-aeda-a2b45bb5654e - Object)"); } public class Issue149_Person { public string Id { get; set; } } public class HazX { public string X { get; set; } } public void SO25297173_DynamicIn() { var query = @" declare @table table(value int not null); insert @table values(1); insert @table values(2); insert @table values(3); insert @table values(4); insert @table values(5); insert @table values(6); insert @table values(7); SELECT value FROM @table WHERE value IN @myIds"; var queryParams = new Dictionary<string, object> { { "myIds", new [] { 5, 6 } } }; var dynamicParams = new DynamicParameters(queryParams); List<int> result = connection.Query<int>(query, dynamicParams).ToList(); result.Count.IsEqualTo(2); result.Contains(5).IsTrue(); result.Contains(6).IsTrue(); } public void AllowIDictionaryParameters() { var parameters = new Dictionary<string, object> { { "param1", 0 } }; connection.Query("SELECT @param1", parameters); } public void Issue178_SqlServer() { const string sql = @"select count(*) from Issue178"; try { connection.Execute("drop table Issue178"); } catch { } try { connection.Execute("create table Issue178(id int not null)"); } catch { } // raw ADO.net var sqlCmd = new SqlCommand(sql, connection); using (IDataReader reader1 = sqlCmd.ExecuteReader()) { Assert.IsTrue(reader1.Read()); reader1.GetInt32(0).IsEqualTo(0); Assert.IsFalse(reader1.Read()); Assert.IsFalse(reader1.NextResult()); } // dapper using (var reader2 = connection.ExecuteReader(sql)) { Assert.IsTrue(reader2.Read()); reader2.GetInt32(0).IsEqualTo(0); Assert.IsFalse(reader2.Read()); Assert.IsFalse(reader2.NextResult()); } } #if EXTERNALS public void Issue178_Firebird() // we expect this to fail due to a bug in Firebird; a PR to fix it has been submitted { var cs = @"initial catalog=localhost:database;user id=SYSDBA;password=masterkey"; using (var connection = new FbConnection(cs)) { connection.Open(); const string sql = @"select count(*) from Issue178"; try { connection.Execute("drop table Issue178"); } catch { } connection.Execute("create table Issue178(id int not null)"); connection.Execute("insert into Issue178(id) values(42)"); // raw ADO.net using (var sqlCmd = new FbCommand(sql, connection)) using (IDataReader reader1 = sqlCmd.ExecuteReader()) { Assert.IsTrue(reader1.Read()); reader1.GetInt32(0).IsEqualTo(1); Assert.IsFalse(reader1.Read()); Assert.IsFalse(reader1.NextResult()); } // dapper using (var reader2 = connection.ExecuteReader(sql)) { Assert.IsTrue(reader2.Read()); reader2.GetInt32(0).IsEqualTo(1); Assert.IsFalse(reader2.Read()); Assert.IsFalse(reader2.NextResult()); } var count = connection.Query<int>(sql).Single(); count.IsEqualTo(1); } } public void PseudoPositionalParameters_Simple() { using (var connection = ConnectViaOledb()) { int value = connection.Query<int>("select ?x? + ?y_2? + ?z?", new { x = 1, y_2 = 3, z = 5, z2 = 24 }).Single(); value.IsEqualTo(9); } } public void PseudoPositionalParameters_Dynamic() { using (var connection = ConnectViaOledb()) { var args = new DynamicParameters(); args.Add("x", 1); args.Add("y_2", 3); args.Add("z", 5); args.Add("z2", 24); int value = connection.Query<int>("select ?x? + ?y_2? + ?z?", args).Single(); value.IsEqualTo(9); } } public void PseudoPositionalParameters_ReusedParameter() { using (var connection = ConnectViaOledb()) { try { int value = connection.Query<int>("select ?x? + ?y_2? + ?x?", new { x = 1, y_2 = 3 }).Single(); Assert.Fail(); } catch (InvalidOperationException ex) { ex.Message.IsEqualTo("When passing parameters by position, each parameter can only be referenced once"); } } } public void PseudoPositionalParameters_ExecSingle() { using (var connection = ConnectViaOledb()) { var data = new { x = 6 }; connection.Execute("create table #named_single(val int not null)"); int count = connection.Execute("insert #named_single (val) values (?x?)", data); int sum = (int)connection.ExecuteScalar("select sum(val) from #named_single"); count.IsEqualTo(1); sum.IsEqualTo(6); } } public void PseudoPositionalParameters_ExecMulti() { using (var connection = ConnectViaOledb()) { var data = new[] { new { x = 1, y = 1 }, new { x = 3, y = 1 }, new { x = 6, y = 1 }, }; connection.Execute("create table #named_multi(val int not null)"); int count = connection.Execute("insert #named_multi (val) values (?x?)", data); int sum = (int)connection.ExecuteScalar("select sum(val) from #named_multi"); count.IsEqualTo(3); sum.IsEqualTo(10); } } #endif public void QueryBasicWithoutQuery() { int? i = connection.Query<int?>("print 'not a query'").FirstOrDefault(); i.IsNull(); } public void QueryComplexWithoutQuery() { var obj = connection.Query<Foo1>("print 'not a query'").FirstOrDefault(); obj.IsNull(); } public void Issue182_BindDynamicObjectParametersAndColumns() { connection.Execute("create table #Dyno ([Id] uniqueidentifier primary key, [Name] nvarchar(50) not null, [Foo] bigint not null);"); var guid = Guid.NewGuid(); var orig = new Dyno { Name = "T Rex", Id = guid, Foo = 123L }; var result = connection.Execute("insert into #Dyno ([Id], [Name], [Foo]) values (@Id, @Name, @Foo);", orig); var fromDb = connection.Query<Dyno>("select * from #Dyno where Id=@Id", orig).Single(); ((Guid)fromDb.Id).IsEqualTo(guid); fromDb.Name.IsEqualTo("T Rex"); ((long)fromDb.Foo).IsEqualTo(123L); } public class Dyno { public dynamic Id { get; set; } public string Name { get; set; } public object Foo { get; set; } } public void Issue151_ExpandoObjectArgsQuery() { dynamic args = new ExpandoObject(); args.Id = 123; args.Name = "abc"; var row = connection.Query("select @Id as [Id], @Name as [Name]", (object)args).Single(); ((int)row.Id).Equals(123); ((string)row.Name).Equals("abc"); } public void Issue151_ExpandoObjectArgsExec() { dynamic args = new ExpandoObject(); args.Id = 123; args.Name = "abc"; connection.Execute("create table #issue151 (Id int not null, Name nvarchar(20) not null)"); connection.Execute("insert #issue151 values(@Id, @Name)", (object)args).IsEqualTo(1); var row = connection.Query("select Id, Name from #issue151").Single(); ((int)row.Id).Equals(123); ((string)row.Name).Equals("abc"); } public void Issue192_InParameterWorksWithSimilarNames() { var rows = connection.Query(@" declare @Issue192 table ( Field INT NOT NULL PRIMARY KEY IDENTITY(1,1), Field_1 INT NOT NULL); insert @Issue192(Field_1) values (1), (2), (3); SELECT * FROM @Issue192 WHERE Field IN @Field AND Field_1 IN @Field_1", new { Field = new[] { 1, 2 }, Field_1 = new[] { 2, 3 } }).Single(); ((int)rows.Field).IsEqualTo(2); ((int)rows.Field_1).IsEqualTo(2); } public void Issue192_InParameterWorksWithSimilarNamesWithUnicode() { var rows = connection.Query(@" declare @Issue192 table ( Field INT NOT NULL PRIMARY KEY IDENTITY(1,1), Field_1 INT NOT NULL); insert @Issue192(Field_1) values (1), (2), (3); SELECT * FROM @Issue192 WHERE Field IN @µ AND Field_1 IN @µµ", new { µ = new[] { 1, 2 }, µµ = new[] { 2, 3 } }).Single(); ((int)rows.Field).IsEqualTo(2); ((int)rows.Field_1).IsEqualTo(2); } class _ExplicitConstructors { public int Field { get; set; } public int Field_1 { get; set; } private bool WentThroughProperConstructor; public _ExplicitConstructors() { } [ExplicitConstructor] public _ExplicitConstructors(string foo, int bar) { WentThroughProperConstructor = true; } public bool GetWentThroughProperConstructor() { return WentThroughProperConstructor; } } public void ExplicitConstructors() { var rows = connection.Query<_ExplicitConstructors>(@" declare @ExplicitConstructors table ( Field INT NOT NULL PRIMARY KEY IDENTITY(1,1), Field_1 INT NOT NULL); insert @ExplicitConstructors(Field_1) values (1); SELECT * FROM @ExplicitConstructors" ).ToList(); rows.Count.IsEqualTo(1); rows[0].Field.IsEqualTo(1); rows[0].Field_1.IsEqualTo(1); rows[0].GetWentThroughProperConstructor().IsTrue(); } public void Issue220_InParameterCanBeSpecifiedInAnyCase() { // note this might fail if your database server is case-sensitive connection.Query<int>("select * from (select 1 as Id) as X where Id in @ids", new { Ids = new[] { 1 } }) .IsSequenceEqualTo(new[] { 1 }); } public void SO29343103_UtcDates() { const string sql = "select @date"; var date = DateTime.UtcNow; var returned = connection.Query<DateTime>(sql, new { date }).Single(); var delta = returned - date; Assert.IsTrue(delta.TotalMilliseconds >= -1 && delta.TotalMilliseconds <= 1); } #if DNXCORE50 [FrameworkFail("https://github.com/dotnet/corefx/issues/1612")] #endif public void Issue261_Decimals() { var parameters = new DynamicParameters(); parameters.Add("c", dbType: DbType.Decimal, direction: ParameterDirection.Output, precision: 10, scale: 5); connection.Execute("create proc #Issue261 @c decimal(10,5) OUTPUT as begin set @c=11.884 end"); connection.Execute("#Issue261", parameters, commandType: CommandType.StoredProcedure); var c = parameters.Get<Decimal>("c"); c.IsEqualTo(11.884M); } #if DNXCORE50 [FrameworkFail("https://github.com/dotnet/corefx/issues/1612")] #endif public void Issue261_Decimals_ADONET_SetViaBaseClass() { Issue261_Decimals_ADONET(true); } public void Issue261_Decimals_ADONET_SetViaConcreteClass() { Issue261_Decimals_ADONET(false); } private void Issue261_Decimals_ADONET(bool setPrecisionScaleViaAbstractApi) { try { using (var cmd = connection.CreateCommand()) { cmd.CommandText = "create proc #Issue261Direct @c decimal(10,5) OUTPUT as begin set @c=11.884 end"; cmd.ExecuteNonQuery(); } } catch { /* we don't care that it already exists */ } using (var cmd = connection.CreateCommand()) { cmd.CommandType = CommandType.StoredProcedure; cmd.CommandText = "#Issue261Direct"; var c = cmd.CreateParameter(); c.ParameterName = "c"; c.Direction = ParameterDirection.Output; c.Value = DBNull.Value; c.DbType = DbType.Decimal; if (setPrecisionScaleViaAbstractApi) { #if DNXCORE50 DbParameter baseParam = c; #else IDbDataParameter baseParam = c; #endif baseParam.Precision = 10; baseParam.Scale = 5; } else { c.Precision = 10; c.Scale = 5; } cmd.Parameters.Add(c); cmd.ExecuteNonQuery(); decimal value = (decimal)c.Value; value.IsEqualTo(11.884M); } } public void BasicDecimals() { var c = connection.Query<decimal>("select @c", new { c = 11.884M }).Single(); c.IsEqualTo(11.884M); } [SkipTest] public void Issue263_Timeout() { var watch = Stopwatch.StartNew(); var i = connection.Query<int>("waitfor delay '00:01:00'; select 42;", commandTimeout: 300, buffered: false).Single(); watch.Stop(); i.IsEqualTo(42); var minutes = watch.ElapsedMilliseconds / 1000 / 60; Assert.IsTrue(minutes >= 0.95 && minutes <= 1.05); } #if EXTERNALS public void SO29596645_TvpProperty() { try { connection.Execute("CREATE TYPE SO29596645_ReminderRuleType AS TABLE (id int NOT NULL)"); } catch { } connection.Execute(@"create proc #SO29596645_Proc (@Id int, @Rules SO29596645_ReminderRuleType READONLY) as begin select @Id + ISNULL((select sum(id) from @Rules), 0); end"); var obj = new SO29596645_OrganisationDTO(); int val = connection.Query<int>("#SO29596645_Proc", obj.Rules, commandType: CommandType.StoredProcedure).Single(); // 4 + 9 + 7 = 20 val.IsEqualTo(20); } #endif public void Issue268_ReturnQueryMultiple() { connection.Execute(@"create proc #TestProc268 (@a int, @b int, @c int)as begin select @a; select @b return @c; end"); var p = new DynamicParameters(new { a = 1, b = 2, c = 3 }); p.Add("RetVal", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue); using (var reader = connection.QueryMultiple("#TestProc268", p, commandType: CommandType.StoredProcedure)) { reader.Read(); } var retVal = p.Get<int>("RetVal"); retVal.IsEqualTo(3); } #if EXTERNALS class SO29596645_RuleTableValuedParameters : Dapper.SqlMapper.IDynamicParameters { private string parameterName; public SO29596645_RuleTableValuedParameters(string parameterName) { this.parameterName = parameterName; } public void AddParameters(IDbCommand command, Dapper.SqlMapper.Identity identity) { Console.WriteLine("> AddParameters"); SqlCommand lazy = (SqlCommand)command; lazy.Parameters.AddWithValue("Id", 7); DataTable table = new DataTable { Columns = {{"Id", typeof(int)}}, Rows = {{4}, {9}} }; lazy.Parameters.AddWithValue("Rules", table); Console.WriteLine("< AddParameters"); } } class SO29596645_OrganisationDTO { public SO29596645_RuleTableValuedParameters Rules { get; private set; } public SO29596645_OrganisationDTO() { Rules = new SO29596645_RuleTableValuedParameters("@Rules"); } } #endif #if POSTGRESQL class Cat { public int Id { get; set; } public string Breed { get; set; } public string Name { get; set; } } Cat[] Cats = { new Cat() { Breed = "Abyssinian", Name="KACTUS"}, new Cat() { Breed = "Aegean cat", Name="KADAFFI"}, new Cat() { Breed = "American Bobtail", Name="KANJI"}, new Cat() { Breed = "Balinese", Name="MACARONI"}, new Cat() { Breed = "Bombay", Name="MACAULAY"}, new Cat() { Breed = "Burmese", Name="MACBETH"}, new Cat() { Breed = "Chartreux", Name="MACGYVER"}, new Cat() { Breed = "German Rex", Name="MACKENZIE"}, new Cat() { Breed = "Javanese", Name="MADISON"}, new Cat() { Breed = "Persian", Name="MAGNA"} }; public void TestPostresqlArrayParameters() { using (var conn = new NpgsqlConnection("Server=localhost;Port=5432;User Id=dappertest;Password=dapperpass;Database=dappertest;Encoding=UNICODE")) { conn.Open(); 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); var r = conn.Query<Cat>("select * from tcat where id=any(:catids)", new { catids = new[] { 1, 3, 5 } }); r.Count().IsEqualTo(3); r.Count(c => c.Id == 1).IsEqualTo(1); r.Count(c => c.Id == 3).IsEqualTo(1); r.Count(c => c.Id == 5).IsEqualTo(1); transaction.Rollback(); } } #endif public void SO30156367_DynamicParamsWithoutExec() { var dbParams = new DynamicParameters(); dbParams.Add("Field1", 1); var value = dbParams.Get<int>("Field1"); value.IsEqualTo(1); } public void SO30435185_InvalidTypeOwner() { try { string sql = @" INSERT INTO #XXX (XXXId, AnotherId, ThirdId, Value, Comment) VALUES (@XXXId, @AnotherId, @ThirdId, @Value, @Comment); select @@rowcount as [Foo]"; var command = new { MyModels = new[] { new {XXXId = 1, AnotherId = 2, ThirdId = 3, Value = "abc", Comment = "def" } } }; var parameters = command .MyModels .Select(model => new { XXXId = model.XXXId, AnotherId = model.AnotherId, ThirdId = model.ThirdId, Value = model.Value, Comment = model.Comment }) .ToArray(); var rowcount = (int)connection.Query(sql, parameters).Single().Foo; rowcount.IsEqualTo(1); Assert.Fail(); } catch(InvalidOperationException ex) { ex.Message.IsEqualTo("An enumerable sequence of parameters (arrays, lists, etc) is not allowed in this context"); } } } } Status API Training Shop Blog About © 2015 GitHub, Inc. Terms Privacy Security Contact