【问题标题】:.NET Dapper nullable cast error.NET Dapper 可为空的强制转换错误
【发布时间】:2013-06-06 19:58:21
【问题描述】:

使用 .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]]

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

立即的答案可能会删除可空值并收工。但是,不起作用的原因是因为我们正在使用同一个类来序列化与 Web 服务之间的记录,并且我们需要能够区分 false 和 null 之间的区别。我曾想过有两个类,一个具有可为空的属性类型,一个没有,但是我需要维护两个类而不是一个类的额外开销。

在属性集期间进行自定义数据转换将是理想的。不过,我在 dapper 文档中没有发现任何内容表明这是可能的。

【问题讨论】:

    标签: .net orm nullable dapper


    【解决方案1】:

    看起来 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));
    

    这行代码不会报错。

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

    【讨论】:

    • 这是否都是作为问题提交给 github 的?
    • 我承认,我从来没有在 Github 上提交过问题。我敢肯定这不是很困难。最后我给开发者发了邮件。他说他会检查的。不知道结果如何。
    【解决方案2】:

    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();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-07
      • 1970-01-01
      • 2011-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多