使用 Dapper
时,有没有遇到过类似的错误
A parameterless default constructor or one matching signature (System.Int32 CustomerID, System.String CustomerName, System.Int32 X) is required for XXX materialization
TL;DR
这是由于目标类 存在含参构造函数ctorA
且 不存在 不含参的构造函数
且 ctorA
与查询结果不一致(参数个数或参数类型)
问题产生
同事正常做功能迭代,已有查询多返回一个字段,改动如下
public class A{
public A(int a,
string b,
+ XXTypeEnum type
)
{
A = a;
B = b;
+ Type = type
}
}
...
var sql = @"SELECT A,
B,
+Type
FROM
...
var result = await connection.Query<A>(sql);
然后就产生了上边类似的报错
A parameterless default constructor or one matching signature (System.Int32 A, System.String C, System.SByte Type) is required for A materialization
问题分析
查了一下这个异常,说明很简单 需要一个无参的构造函数 或者 一个匹配签名的构造函数
,加一个空的构造函数试了的确是可以,但是为什么如此呢,看着现有的构造函数也是匹配的,仔细看下Type参数的类型并不匹配
debug 几次,得出如下结果
- 不存在无参构造函数,自动映射(显式转换(比如
int
->enum
)) - 存在含参构造函数,查找对应类型,对应参数的构造函数(此处不会默认显式转换,比如枚举)
- 存在无参构造函数,无参构造函数会正常调用,但是以最终映射为准
结论
对于 Dapper 对应结果 Model类, 最好是不写含参ctor,如果写了含参的ctor 也要写一个 不含参的ctor(private 也可以)
ps. 使用Mysql 数据库,系统枚举值使用了 tinyint(4)
, GetFieldType
结果为 System.SByte
,附一个 tinyint
类型对应
mysql Type | FieldType |
---|---|
tinyint(1) | System.Boolean *可以通过修改连接字符串 TreatTinyAsBoolean=false 为System.SByte |
tinyint | System.SByte |
tinyint unsigned | System.Byte |
pps. 8.0.17 中已弃用整数数据类型的显示宽度 , tinyint(1)
除外,所以最好不要用tinyint(x)
的写法 具体可看mysql 8.0.19 feature