diff --git a/SqlMapper.cs b/SqlMapper.cs index 16b3dbf7..b7e91e77 100644 --- a/SqlMapper.cs +++ b/SqlMapper.cs @@ -118,10 +118,26 @@ namespace SqlMapper return ExecuteCommand(cnn, transaction, sql, GetParamInfo(param)); } + + static class DynamicStub + { + public static Type Type = typeof(DynamicStub); + } + public static List ExecuteMapperQuery (this IDbConnection cnn, string sql, object param = null, SqlTransaction transaction = null) { - // TODO: get rid of casting hackery - return ExecuteMapperQuery(cnn, sql, param, transaction).Select(s => s as dynamic).ToList(); + var identity = new Identity(sql, DynamicStub.Type); + var list = new List(); + + using (var reader = GetReader(cnn, transaction, sql, GetParamInfo(param))) + { + Func deserializer = GetDeserializer(identity, reader); + while (reader.Read()) + { + list.Add(deserializer(reader)); + } + } + return list; } @@ -132,25 +148,7 @@ namespace SqlMapper using (var reader = GetReader(cnn, transaction, sql, GetParamInfo(param))) { - object oDeserializer; - if (!cachedSerializers.TryGetValue(identity, out oDeserializer)) - { - if (typeof(T) == typeof(ExpandoObject)) - { - oDeserializer = GetDynamicDeserializer(reader); - } - else if (typeof(T).IsClass && typeof(T) != typeof(string)) - { - oDeserializer = GetClassDeserializer(reader); - } - else - { - oDeserializer = GetStructDeserializer(reader); - } - - cachedSerializers[identity] = oDeserializer; - } - Func deserializer = (Func)oDeserializer; + Func deserializer = GetDeserializer(identity, reader); while (reader.Read()) { rval.Add(deserializer(reader)); @@ -162,6 +160,30 @@ namespace SqlMapper return rval; } + private static Func GetDeserializer(Identity identity, IDataReader reader) + { + object oDeserializer; + if (!cachedSerializers.TryGetValue(identity, out oDeserializer)) + { + if (typeof(T) == DynamicStub.Type || typeof(T) == typeof(ExpandoObject)) + { + oDeserializer = GetDynamicDeserializer(reader); + } + else if (typeof(T).IsClass && typeof(T) != typeof(string)) + { + oDeserializer = GetClassDeserializer(reader); + } + else + { + oDeserializer = GetStructDeserializer(reader); + } + + cachedSerializers[identity] = oDeserializer; + } + Func deserializer = (Func)oDeserializer; + return deserializer; + } + private static List GetParamInfo(object param) { Func> paramInfoGenerator; diff --git a/Tests.cs b/Tests.cs index 05e65a74..a8dc3bd6 100644 --- a/Tests.cs +++ b/Tests.cs @@ -9,7 +9,7 @@ namespace SqlMapper static class TestAssertions { - public static void IsEquals(this T obj, T other) + public static void IsEqualTo(this T obj, T other) { if (!obj.Equals(other)) { @@ -17,7 +17,7 @@ namespace SqlMapper } } - public static void IsSequenceEqual(this IEnumerable obj, IEnumerable other) + public static void IsSequenceEqualTo(this IEnumerable obj, IEnumerable other) { if (!obj.SequenceEqual(other)) { @@ -51,20 +51,20 @@ namespace SqlMapper public void SelectListInt() { connection.ExecuteMapperQuery("select 1 union all select 2 union all select 3") - .IsSequenceEqual(new[] { 1, 2, 3 }); + .IsSequenceEqualTo(new[] { 1, 2, 3 }); } public void PassInIntArray() { connection.ExecuteMapperQuery("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() }) - .IsSequenceEqual(new[] { 1, 2, 3 }); + .IsSequenceEqualTo(new[] { 1, 2, 3 }); } public void TestDoubleParam() { connection.ExecuteMapperQuery("select @d", new { d = 0.1d }).First() - .IsEquals(0.1d); + .IsEqualTo(0.1d); } public void TestBoolParam() @@ -76,7 +76,7 @@ namespace SqlMapper public void TestStrings() { connection.ExecuteMapperQuery(@"select 'a' a union select 'b'") - .IsSequenceEqual(new[] { "a", "b" }); + .IsSequenceEqualTo(new[] { "a", "b" }); } public class Dog @@ -95,13 +95,13 @@ namespace SqlMapper var dog = connection.ExecuteMapperQuery("select Age = @Age, Id = @Id", new { Age = (int?)null, Id = guid }); dog.Count() - .IsEquals(1); + .IsEqualTo(1); dog.First().Age .IsNull(); dog.First().Id - .IsEquals(guid); + .IsEqualTo(guid); } public void TestExpando() @@ -109,22 +109,22 @@ namespace SqlMapper var rows = connection.ExecuteMapperQuery("select 1 A, 2 B union all select 3, 4"); ((int)rows[0].A) - .IsEquals(1); + .IsEqualTo(1); ((int)rows[0].B) - .IsEquals(2); + .IsEqualTo(2); ((int)rows[1].A) - .IsEquals(3); + .IsEqualTo(3); ((int)rows[1].B) - .IsEquals(4); + .IsEqualTo(4); } public void TestStringList() { connection.ExecuteMapperQuery("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"}}) - .IsSequenceEqual(new[] {"a","b","c"}); + .IsSequenceEqualTo(new[] {"a","b","c"}); } public void TestExecuteCommand() @@ -136,14 +136,14 @@ namespace SqlMapper insert #t select @a a union all select @b set nocount on - drop table #t", new {a=1, b=2 }).IsEquals(2); + drop table #t", new {a=1, b=2 }).IsEqualTo(2); } public void TestMassiveStrings() { var str = new string('X', 20000); connection.ExecuteMapperQuery("select @a", new { a = str }).First() - .IsEquals(str); + .IsEqualTo(str); } }