When selecting a single column result for a custom type that is nullable, DBNull is passed to the type handler normally resulting in an InvalidCastException as the type handler is not expecting a null. Since the type handler can't return null either, it has no sensible way to handle the DBNull.
voidMain(){SqlMapper.AddTypeHandler(newMoneyTypeHandler());using(vardb=newSqlConnection("Server=(local); Integrated Security=SSPI")){db.Open();// Normal CLR types work fine when nullabledb.Query<int?>("SELECT 1").Single().Dump();db.Query<int?>("SELECT NULL").Single().Dump();// Nullable custom type works correctly when used as a propertydb.Query<Foo>("SELECT 1 AS Cost").Single().Dump();db.Query<Foo>("SELECT NULL AS Cost").Single().Dump();// Fails when used as a single column scalar resultdb.Query<Money?>("SELECT 1").Single().Dump();db.Query<Money?>("SELECT NULL").Single().Dump();}}publicclassMoneyTypeHandler:SqlMapper.TypeHandler<Money>{publicoverridevoidSetValue(IDbDataParameterp,Moneyvalue){p.DbType=DbType.Int32;p.Value=value.Value;}publicoverrideMoneyParse(objectobj){if(objisDBNull){thrownewInvalidCastException("Expected type int, got type DBNull");}returnnewMoney((int)obj);}}publicstructMoney{privatereadonlyintvalue;publicMoney(intvalue){this.value=value;}publicintValue{get{returnvalue;}}}publicclassFoo{publicMoney?Cost{get;set;}}
When selecting a single column result for a custom type that is nullable, DBNull is passed to the type handler normally resulting in an
InvalidCastExceptionas the type handler is not expecting a null. Since the type handler can't return null either, it has no sensible way to handle the DBNull.