oracle number 超出 c# decimal 范围时直接抛 overflowexception,应优先使用 oraclenumber 接收并校验 isvalid/isfinite 后再转换,ef core 中需改用 oraclenumber? 或显式指定列精度,废弃 oracledecimal。
oracle number 超出 decimal 范围时会直接抛异常
不是静默截断,也不是四舍五入——只要 oracle 返回的 number 值超出 c# decimal 的表示范围(±79,228,162,514,264,337,593,543,950,335),oracledatareader.getdecimal() 或 oracledataadapter.fill() 就会炸,报 system.overflowexception: value was either too large or too small for a decimal.。这在处理老库中用 number(38) 存大整数(比如时间戳、id 序列)或极高精度小数时特别常见。
实操建议:
- 别依赖默认的
GetDecimal(),先用GetFieldValue<object>(i)</object>或GetValue(i)拿原始值,再判断类型 -
OracleNumber是 Oracle 官方提供的“安全中间层”,它能承载完整NUMBER精度,且不抛溢出异常——但你得手动转 - 如果字段确定不会溢出(比如业务上就是金额,最多 2 位小数 + 12 位整数),可在数据库侧加 CHECK 约束或应用层做前置校验
用 OracleNumber 接收再按需转 decimal 或字符串
OracleNumber 是 Oracle Data Provider for .NET(ODP.NET)里专为绕过 decimal 溢出设计的类型,它内部用三部分(符号、系数、指数)模拟 Oracle NUMBER,支持全部 38 位精度和 127 位指数范围。
实操建议:
- 读取时优先用
reader.GetOracleNumber(i),而不是GetDecimal(i) - 转
decimal前必须调用.IsValid判断是否可安全转换:on.IsValid && on.IsFinite,否则仍可能溢出 - 对超大整数(如
NUMBER(38,0)),直接转ToString()更稳妥,避免丢失精度;C#decimal最多 29 位有效数字,而NUMBER(38)可能有 38 位 - 注意:
OracleNumber.Null和DBNull.Value不等价,判空要用on.IsNull
Entity Framework Core 中映射 NUMBER 的陷阱
EF Core 默认把 Oracle NUMBER 映射成 decimal,一旦数据越界,SaveChanges() 或查询时照样崩。它不自动 fallback 到 OracleNumber,也不提供全局配置开关。
实操建议:
- 实体属性别硬写
decimal,改用OracleNumber?(需引用Oracle.ManagedDataAccess.Core) - 自定义
ValueConverter<oraclenumber string></oraclenumber>把超长数值存为字符串,适合只读场景或 ID 类字段 - 若必须用
decimal属性,得在OnModelCreating里显式指定精度:property.HasColumnType("NUMBER(18,2)"),让 Oracle 层面约束输入 - 迁移脚本生成的
NUMBER默认是NUMBER(*,*),实际建表时可能变成NUMBER(38),务必检查 DDL
OracleDecimal 已废弃,别用
OracleDecimal 是 ODP.NET 旧版(非托管驱动)里的类型,在当前主流的 Oracle.ManagedDataAccess(托管驱动)中已被移除。代码里如果还留着这个类型,编译就过不去;就算侥幸存在,它也不解决溢出问题,只是 decimal 的一层薄包装。
实操建议:
- 搜索整个项目,删掉所有
using Oracle.DataAccess.Types;和OracleDecimal相关代码 - 确认 NuGet 引用的是
Oracle.ManagedDataAccess(≥ 19.x)或Oracle.ManagedDataAccess.Core,不是已停更的Oracle.DataAccess - 替换路径:原
OracleDecimal→ 改用OracleNumber;原Oracle.DataAccess.Client→ 改用Oracle.ManagedDataAccess.Client
最麻烦的不是写代码,而是老系统里那些没文档的 NUMBER 字段——你永远不知道它哪天突然塞进来一个 1e38 的数。上线前务必用真实生产数据集跑一遍全量字段扫描,别只测 happy path。










