Dapper 默认将 NUMERIC/DECIMAL 映射为 C# decimal 且不截断或四舍五入,精度依赖数据库列定义(如 NUMERIC(18,4))、驱动(推荐 Microsoft.Data.SqlClient)及 SQL 写法(如用 1.0m 而非 1.0),需避免 FLOAT、隐式转换和旧版驱动缺陷。

Dapper 默认会将数据库中的 NUMERIC(或 DECIMAL)类型映射为 C# 的 decimal,精度和小数位数基本能保持一致,但实际行为取决于数据库驱动(如 SqlClient、Npgsql、MySqlConnector)和列定义,不是 Dapper 自身“处理”精度,而是它忠实地传递驱动返回的值。关键在于:Dapper 不做截断、四舍五入或隐式转换,但若底层驱动或数据库连接配置不当,就可能出问题。
确保数据库列定义与 C# decimal 匹配
SQL Server 中定义列时应明确指定精度和小数位,例如:NUMERIC(18, 4)。这样 SqlClient 驱动读取时会返回对应精度的 decimal 值。如果只写 NUMERIC(无参数),不同数据库默认行为不同(SQL Server 默认是 (18,0)),可能导致小数部分被截断。
- 建表时显式声明精度,比如
Amount NUMERIC(19,6) - 避免用
FLOAT或REAL存金额——它们是近似值,无法精确表示 0.1 这类数字 - 查询时别用
CAST/CONVERT无意降低精度,例如CONVERT(NUMERIC(10,2), value)会强制四舍五入
检查数据库驱动是否正确返回 decimal
某些旧版驱动(如早期 .NET Framework 的 System.Data.SqlClient)在特定场景下可能把 NUMERIC 当作 double 返回,尤其当列未指定精度或连接字符串含 Column Encryption Setting=Enabled 等特殊配置时。
- 推荐使用
Microsoft.Data.SqlClient(.NET Core+ 主流选择),它对decimal支持更严格 - 运行时可验证:查出值后用
value.GetType()确认是System.Decimal,不是Double或Object - Npgsql(PostgreSQL)默认也映射为
decimal,但若字段是money类型,则需注意它会转成decimal且自动保留 2 位小数
避免在 Dapper 查询中隐式丢失精度
Dapper 执行 SQL 时不会修改数据,但如果你在 SQL 里做了运算或用了函数,就可能触发隐式转换。例如:
-
SELECT price * 1.0 FROM products——1.0是float字面量,整个表达式可能升格为float,导致精度丢失 - 改用
price * 1.0m(m后缀表示decimal字面量) -
聚合函数如
AVG()在 SQL Server 中默认返回float,应显式转换:CAST(AVG(price) AS NUMERIC(18,4))
插入/更新时注意参数绑定精度
Dapper 绑定 decimal 参数时,会通过 ADO.NET 的 SqlParameter(SQL Server)等机制传入。只要 C# 变量是 decimal,驱动一般能推断合适精度;但极端情况下(如超大精度 decimal),可手动指定:
- 使用
new DbParameter { Value = amount, DbType = DbType.Decimal, Precision = 18, Scale = 6 }(需自定义 DynamicParameters 或继承 ParameterizedType) - 多数情况无需手动设,因为现代驱动(如 Microsoft.Data.SqlClient v5+)会根据
decimal实际值自动设置合适的Precision和Scale - 测试方法:插入
123.456789m,再查出来看是否完全一致
基本上就这些。Dapper 本身不干预 decimal 精度,它靠的是底层驱动和 SQL 定义的配合。只要数据库列定义清晰、驱动版本不过时、SQL 写法规范,decimal 就能原样进出,一分不差。










