列中的NULL值的Dapper Cast异常

时间:2018-01-09 16:04:56

标签: c# sqlite dapper

我正在使用SQLite和它的闭包扩展来存储层次结构。非闭包表创建为

_connection.Execute(@"CREATE TABLE IF NOT EXISTS category (
    id INTEGER NOT NULL PRIMARY KEY,
    name TEXT,
    parent_id INTEGER,
    FOREIGN KEY (parent_id) REFERENCES category (id)
);");

插入根节点时parent_id设置为NULL。 Dapper要转换的类是

public class TestRecord
{
    public long id;
    public string name;
    public long? parent_id;
}

在我看来,Dapper在读取根节点或非根节点时不应该有任何问题,因为有问题的列明显标记为可为空。但是,查询所有条目如下:

_connection.Query<TestRecord>(@"SELECT * FROM category;");

将抛出根节点,因为它无法投射某些东西(这很奇怪,因为任何地方都没有涉及32位的int):

Unhandled Exception: System.Data.DataException: 
Error parsing column 2 (parent_id=1 - Int64) ---> 
System.InvalidCastException: Unable to cast object of type 'System.Int64' to type 
  'System.Int32'.

返回正确结果的解决方法

.Query<TestRecord>(@"SELECT id, IFNULL(parent_id, 0), name FROM category;");

但出于几个原因,这是不行的。我特别不想列出查询中的所有列,也不想介绍parent_id特殊情况。

不使用Dapper并手动映射它可以很好地处理原始查询,当然也适用于sqlite CLI。

那么,我怎样才能让Dapper接受并映射正确的条目?

编辑:我正在使用Dapper 1.50.4和dotnet core 2.0。

4 个答案:

答案 0 :(得分:2)

Marc's comment这不应该发生,并且它会修复库修复。该问题正在跟踪here,也会影响其他人。

答案 1 :(得分:2)

sqlite可为空类型的解决方案。 link

public class NullableLongHandler : SqlMapper.TypeHandler<long?>
{
    public override void SetValue(IDbDataParameter parameter, long? value)
    {
        if (value.HasValue)
            parameter.Value = value.Value;
        else
            parameter.Value = DBNull.Value;
    }

    public override long? Parse(object value)
    {
        if (value == null || value is DBNull) return null;
        return Convert.ToInt64(value);
    }
}

SqlMapper.AddTypeHandler(new NullableLongHandler());

答案 2 :(得分:0)

如果使用“INTEGER”创建表,Sqlite将创建int32,但是你的模型中有一个很长的时间,我想这是无效的强制转换异常,BigInt必须用来给出一个长的。

因此,您应该将请求更改为:

_connection.Execute(@"CREATE TABLE IF NOT EXISTS category (
  id BIGINT NOT NULL PRIMARY KEY,
  name TEXT,
  parent_id BIGINT,
  FOREIGN KEY (parent_id) REFERENCES category (id)
);");

或使用符合您要求的型号:

public class TestRecord
{
    public int id;
    public string name;
    public int? parent_id;
}

我猜你的“IFNULL(parent_id,0)”请求正在运行,因为它包含一个强制类型,因为0可以被认为是int32。

答案 3 :(得分:-1)

尝试使用此类,它应该工作

public class TestRecord
{
    public Int64 id;
    public string name;
    public Int64? parent_id;
}

<强>更新

尝试

public class TestRecord
{
    public Int32 id;
    public string name;
    public Int32? parent_id;
}

因为这是你的错误

System.InvalidCastException: Unable to cast object of type 'System.Int64' to type 
  'System.Int32'.

因为如果这个错误意味着它无法转换为int32到int64,那么最好更改基本数据的类型