我正在使用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位整数):
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。
sqlite可为空类型的解决方案。 链接
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());