Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions Dapper/SqlMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3854,10 +3854,12 @@ private static void LoadReaderValueOrBranchToDBNullLabel(ILGenerator il, int ind
// note the TypeCode tests are only meaningful for distinct codes: TypeCode.Object
// matching TypeCode.Object says nothing (TimeSpan vs TimeOnly?, say), and a direct
// unbox there throws; such pairs belong to the flexible-convert path below. A column
// reported as plain *object* (sql_variant etc) keeps the direct unbox: the runtime
// box is the only truth available there
// reported as plain *object* (sql_variant etc) keeps the direct unbox for targets that
// are themselves TypeCode.Object: the runtime box is the only truth available there,
// and a primitive target still needs the conversion (an int box for a bool member)
if ((hasTypeHandler = typeHandlers.ContainsKey(unboxType)) || colType == unboxType
|| colType == typeof(object) || unboxType == typeof(object)
|| (colType == typeof(object) && Type.GetTypeCode(nullUnderlyingType ?? unboxType) == TypeCode.Object)
|| unboxType == typeof(object)
|| (dataTypeCode == unboxTypeCode && dataTypeCode != TypeCode.Object)
|| (dataTypeCode == Type.GetTypeCode(nullUnderlyingType) && dataTypeCode != TypeCode.Object)
|| colType == nullUnderlyingType)
Expand Down
40 changes: 39 additions & 1 deletion tests/Dapper.Tests/DataReaderTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using Xunit;
Expand Down Expand Up @@ -93,6 +95,42 @@ public void TestTreatIntAsABool()
Assert.True(SqlMapper.Parse<bool>(reader).Single());
}

[Fact]
public void ObjectTypedColumnsConvertToMemberType()
{
// a provider that reports a column as plain object (sql_variant, say) hands back whatever it boxed
var guid = new Guid("5a6ab3c0-7a1e-4f3e-9d34-2d6a1b7e4c11");
var table = new DataTable();
table.Columns.Add("Flag", typeof(object));
table.Columns.Add("NullableFlag", typeof(object));
table.Columns.Add("Count", typeof(object));
table.Columns.Add("Id", typeof(object));
table.Columns.Add("NullableId", typeof(object));
table.Rows.Add(1, 0, 42, guid, guid);

var row = table.CreateDataReader().Parse<HazObjectColumns>().Single();
Assert.True(row.Flag);
Assert.False(row.NullableFlag);
Assert.Equal(42L, row.Count);
Assert.Equal(guid, row.Id);
Assert.Equal(guid, row.NullableId);
}

[Fact] // #2234
public void SqlVariantIntToBool()
{
Assert.True(connection.QuerySingle<HazObjectColumns>("select cast(cast(1 as int) as sql_variant) as Flag").Flag);
}

private class HazObjectColumns
{
public bool Flag { get; set; }
public bool? NullableFlag { get; set; }
public long Count { get; set; }
public Guid Id { get; set; }
public Guid? NullableId { get; set; }
}

[Fact]
public void DiscriminatedUnion_IDataReader()
{
Expand Down