diff --git a/Dapper.Tests/Tests.QueryMultiple.cs b/Dapper.Tests/Tests.QueryMultiple.cs index 537c31519..94ea711ae 100644 --- a/Dapper.Tests/Tests.QueryMultiple.cs +++ b/Dapper.Tests/Tests.QueryMultiple.cs @@ -141,7 +141,7 @@ public void Issue524_QueryMultiple_Cast() { // aka: Read should work even if the data is a // using regular API - connection.Query("select cast(42 as bigint)").IsEqualTo(42); + connection.Query("select cast(42 as bigint)").Single().IsEqualTo(42); connection.QuerySingle("select cast(42 as bigint)").IsEqualTo(42); // using multi-reader API diff --git a/Dapper/SqlMapper.GridReader.Async.cs b/Dapper/SqlMapper.GridReader.Async.cs index d0deb0bc8..74ba904c3 100644 --- a/Dapper/SqlMapper.GridReader.Async.cs +++ b/Dapper/SqlMapper.GridReader.Async.cs @@ -181,7 +181,7 @@ private Task> ReadAsyncImpl(Type type, bool buffered) } else { - var result = ReadDeferred(gridIndex, deserializer.Func, typedIdentity); + var result = ReadDeferred(gridIndex, deserializer.Func, typedIdentity, type); if (buffered) result = result.ToList(); // for the "not a DbDataReader" scenario return Task.FromResult(result); } diff --git a/Dapper/SqlMapper.GridReader.cs b/Dapper/SqlMapper.GridReader.cs index 0721ed7d7..71f8d2ac6 100644 --- a/Dapper/SqlMapper.GridReader.cs +++ b/Dapper/SqlMapper.GridReader.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Data; using System.Linq; - +using System.Globalization; namespace Dapper { partial class SqlMapper @@ -161,7 +161,7 @@ private IEnumerable ReadImpl(Type type, bool buffered) cache.Deserializer = deserializer; } IsConsumed = true; - var result = ReadDeferred(gridIndex, deserializer.Func, typedIdentity); + var result = ReadDeferred(gridIndex, deserializer.Func, typedIdentity, type); return buffered ? result.ToList() : result; } @@ -184,8 +184,16 @@ private T ReadRow(Type type, Row row) deserializer = new DeserializerState(hash, GetDeserializer(type, reader, 0, -1, false)); cache.Deserializer = deserializer; } - result = (T) deserializer.Func(reader); - if ((row & Row.Single) != 0 && reader.Read()) ThrowMultipleRows(row); while (reader.Read()) { } + object val = deserializer.Func(reader); + if(val == null || val is T) + { + result = (T)val; + } else { + var convertToType = Nullable.GetUnderlyingType(type) ?? type; + result = (T)Convert.ChangeType(val, convertToType, CultureInfo.InvariantCulture); + } + if ((row & Row.Single) != 0 && reader.Read()) ThrowMultipleRows(row); + while (reader.Read()) { } } else if((row & Row.FirstOrDefault) == 0) // demanding a row, and don't have one { @@ -297,13 +305,19 @@ public IEnumerable Read(Type[] types, Func return buffered ? result.ToList() : result; } - private IEnumerable ReadDeferred(int index, Func deserializer, Identity typedIdentity) + private IEnumerable ReadDeferred(int index, Func deserializer, Identity typedIdentity, Type effectiveType) { try { + var convertToType = Nullable.GetUnderlyingType(effectiveType) ?? effectiveType; while (index == gridIndex && reader.Read()) { - yield return (T)deserializer(reader); + object val = deserializer(reader); + if (val == null || val is T) { + yield return (T)val; + } else { + yield return (T)Convert.ChangeType(val, convertToType, CultureInfo.InvariantCulture); + } } } finally // finally so that First etc progresses things even when multiple rows