在使用Dapper操作MySQL数据库时,无符号整型字段的映射是很多开发者都会遇到的典型问题。MySQL的UNSIGNED类型的取值范围和C#默认的有符号整型存在差异,如果直接使用默认的映射规则,很容易出现数据转换错误或者查询执行异常的情况。

MySQL UNSIGNED类型的取值范围
MySQL中常见的无符号整型包括TINYINT UNSIGNED、SMALLINT UNSIGNED、INT UNSIGNED、BIGINT UNSIGNED,它们和C#内置整型的取值范围对比如下:
| MySQL类型 | MySQL取值范围 | C#对应有符号类型 | C#有符号类型取值范围 |
|---|---|---|---|
| TINYINT UNSIGNED | 0 ~ 255 | byte | -128 ~ 127 |
| SMALLINT UNSIGNED | 0 ~ 65535 | ushort | -32768 ~ 32767 |
| INT UNSIGNED | 0 ~ 4294967295 | uint | -2147483648 ~ 2147483647 |
| BIGINT UNSIGNED | 0 ~ 18446744073709551615 | ulong | -9223372036854775808 ~ 9223372036854775807 |
可以看到除了TINYINT UNSIGNED和C#的byte类型取值范围匹配之外,其余的无符号整型如果使用C#默认的有符号整型接收,都可能出现取值溢出的问题。
Dapper默认映射的问题
Dapper默认的映射规则会尝试将MySQL的整型字段映射到C#的int类型,当字段是INT UNSIGNED且存储的值超过int的最大值2147483647时,执行查询就会抛出数据转换异常。比如我们有如下的MySQL表结构:
CREATE TABLE user_info (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
age TINYINT UNSIGNED NOT NULL,
total_score INT UNSIGNED NOT NULL
);
如果对应的C#实体类定义如下,查询时就会出现问题:
public class UserInfo
{
// 这里用int接收INT UNSIGNED,值超过2147483647会报错
public int Id { get; set; }
// 用int接收TINYINT UNSIGNED,值超过127会报错
public int Age { get; set; }
// 用int接收INT UNSIGNED,值超过2147483647会报错
public int TotalScore { get; set; }
}
执行查询代码时就会抛出异常:
using Dapper;
using MySql.Data.MySqlClient;
string connStr = "Server=127.0.0.1;Database=test;Uid=root;Pwd=123456;";
using (var conn = new MySqlConnection(connStr))
{
// 当total_score的值超过2147483647时,这里会抛出转换异常
var user = conn.QueryFirstOrDefault<UserInfo>("SELECT * FROM user_info WHERE id = 1");
}
解决方案一:调整实体类类型定义
最直接的方式是将实体类中对应无符号整型的属性类型,修改为C#的无符号类型,和MySQL的UNSIGNED类型取值范围匹配:
public class UserInfo
{
// INT UNSIGNED对应uint
public uint Id { get; set; }
// TINYINT UNSIGNED对应byte
public byte Age { get; set; }
// INT UNSIGNED对应uint
public uint TotalScore { get; set; }
}
这种方式的优点是简单直接,不需要额外的配置,适合大部分场景。但需要注意C#的无符号类型在部分框架或者序列化场景中可能支持不够完善,需要根据实际项目情况选择。
解决方案二:自定义Dapper类型处理器
如果项目中不希望使用C#的无符号类型,可以通过自定义Dapper的TypeHandler来实现映射转换,比如将INT UNSIGNED映射到long类型:
using Dapper;
using System;
using System.Data;
// 自定义INT UNSIGNED到long的处理器
public class UIntToInt64Handler : SqlMapper.TypeHandler<long>
{
public override long Parse(object value)
{
// 将MySQL返回的无符号整型值转换为long
if (value is uint uintValue)
{
return uintValue;
}
if (value is ulong ulongValue)
{
return (long)ulongValue;
}
return Convert.ToInt64(value);
}
public override void SetValue(IDbDataParameter parameter, long value)
{
parameter.Value = value;
}
}
然后在程序启动时注册这个处理器:
// 程序启动时注册自定义处理器 SqlMapper.AddTypeHandler(new UIntToInt64Handler());
之后实体类就可以使用long类型接收INT UNSIGNED字段:
public class UserInfo
{
public long Id { get; set; }
public byte Age { get; set; }
public long TotalScore { get; set; }
}
解决方案三:修改数据库字段类型
如果项目允许调整数据库结构,可以将UNSIGNED类型修改为有符号类型,同时调整字段的取值范围约束,比如将INT UNSIGNED修改为INT,然后添加CHECK约束保证值不为负数:
-- 修改字段类型,去掉UNSIGNED,添加非负约束 ALTER TABLE user_info MODIFY COLUMN id INT AUTO_INCREMENT, MODIFY COLUMN total_score INT NOT NULL, ADD CONSTRAINT chk_total_score_nonnegative CHECK (total_score >= 0);
这种方式可以从数据库层面避免无符号类型带来的映射问题,适合新项目或者可以调整数据库结构的场景。
注意事项
- 使用自定义类型处理器时,需要注意不同MySQL版本返回的数据类型可能有差异,需要在Parse方法中做好类型判断。
- 如果使用的是
BIGINT UNSIGNED类型,即使使用long类型也可能出现溢出,此时建议还是使用ulong或者自定义处理器转换为字符串类型存储。 - 插入或者更新无符号整型字段时,也需要保证传入的值符合MySQL字段的取值范围,避免出现数据库层面的插入错误。
DapperMySQLUNSIGNED类型无符号整型映射修改时间:2026-06-20 23:48:40