.NET Dapper可以为空的强制转换错误

时间:2013-06-06 19:58:22

标签: .net orm nullable dapper

使用.NET Dapper,我在获取包含整数值(0/1)的数据库字段时遇到问题,该字段映射到类中可以为空的布尔属性。

为了简单起见,我已经删除并将该类重命名为重现问题所需的最低限度:

public class Test
{
    public bool? TestField { get; set; }
}

如果调用以下代码来填充Test类:

var Results = DBConnection.Query<Test>("SELECT 0 As TestField]").ToList();

将抛出以下错误:

Invalid cast from 'System.Int32' to 'System.Nullable`1[[System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]

如果我删除问号,使该字段成为不可空的布尔值(即公共 bool TestField),一切正常。

立即回答可能似乎删除了可空,并将其称为一天。但是,无法工作的原因是因为我们使用同一个类来序列化Web服务的记录,我们需要能够区分false和null。我想过有两个类,一个具有可空属性类型,一个没有,但是后来我增加了维护两个类而不是一个类的开销。

属性集期间的自定义数据转换将是理想的。虽然,我没有在短小精悍的文档中找到任何建议,甚至可以这样做。

2 个答案:

答案 0 :(得分:3)

在Dapper代码中可能存在关于可以为空的bool / long等问题。

以下是源代码中的三行(第2375-2377行版本1.12.1.1)。问题出在第一行:

il.Emit(OpCodes.Ldtoken, unboxType); // stack is now [target][target][value][member-type-token]
il.EmitCall(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"), null); // stack is now [target][target][value][member-type]
il.EmitCall(OpCodes.Call, typeof(Convert).GetMethod("ChangeType", new Type[] { typeof(object), typeof(Type) }), null); // stack is now [target][target][boxed-member-type-value]

发出此代码时,它将等同于以下代码行:

Convert.ChangeType(0, typeof(bool?));

不幸的是,这会引发我所看到的错误。通过将上面的第一个il.Emit()行更改为以下内容:

il.Emit(OpCodes.Ldtoken, nullUnderlyingType ?? memberType); // stack is now [target][target][value][member-type-token]

生成的等效代码行变成了这一点,注意到最后的typeof(bool?)不再有可以为空的问号:

Convert.ChangeType(0, typeof(bool));

这行代码不会引发错误。

所以解决方案是重新编译源代码。我会将此更改提交给项目,供他们审核,看看是否会产生任何不必要的副作用。

答案 1 :(得分:0)

Bit应该很好地映射到bool:

create table Test
(
    TestField bit null
)

另一种选择是做类似的事情:

var Results = DBConnection.Query<Test>("SELECT cast(case TestField when 1 then 1 when 0 then 0 else null end as bit)  As TestField from Test").ToList();