oracle的number类型必须显式控制精度、标量类型和驱动配置,否则映射易错;number(p,0)按p值硬编码映射c#类型,如(1,0)默认int16需手动转bool;新版ef core需hasconversion+app.config中edmmapping双配置,且nls参数异常会导致隐式转换失败。

Oracle的NUMBER类型不能靠默认映射“蒙对”,必须显式控制精度、标量类型和驱动级配置,否则bool变short、int变decimal都是常态。
NUMBER(p,0)精度决定C#基础类型,不是看列名或业务含义
Oracle里没有BIT、TINYINT这些类型,全靠NUMBER(p,s)的精度p(总位数)和小数位s推断。EF Core(含Oracle EF Core提供程序)按p值做硬编码映射:
-
NUMBER(1,0)→ 默认Int16,但常需映射为bool(如IS_ACTIVE字段) -
NUMBER(3,0)→ 默认Int16,可配为byte(对应SQL ServerTINYINT) -
NUMBER(10,0)→ 理论上刚好覆盖int.MaxValue(2147483647),但Oracle EF Core提供程序实际用NUMBER(11,0)才映射到int -
NUMBER(19,0)→ 自动升为decimal,无法绕过
你在实体中写public bool IsDeleted { get; set; },但数据库列是NUMBER(2,0),EF Core照样当short读——不会报错,但值会错乱。
用HasColumnType("odp_internal_use_type")强行指定EDM类型(仅限旧版ODP.NET)
早期Oracle EF Provider(非Oracle.EntityFrameworkCore)支持用特殊字符串覆盖默认映射,比如把NUMBER(1,0)列强制当bool用:
Property(p => p.IsFixed)
.HasColumnName("IS_FIXED")
.HasColumnType("odp_internal_use_type");
这个字符串是ODP.NET内部识别的占位符,不是真实SQL类型。它依赖app.config中<oracle.dataaccess.client></oracle.dataaccess.client>节的自定义映射配置生效。新版Oracle.EntityFrameworkCore已弃用此机制,改用以下方式。
新版Oracle EF Core:用HasConversion + 配置文件双保险
从Oracle.EntityFrameworkCore 5.0+开始,推荐组合使用:
-
HasConversion<bool int>()</bool>在模型中声明转换逻辑 -
appsettings.json或app.config中配置<oracle.manageddataaccess.client></oracle.manageddataaccess.client>节,让驱动层也认NUMBER(1,0) → bool
示例(实体配置):
modelBuilder.Entity<order>()
.Property(e => e.IsActive)
.HasConversion<bool int>(
toDb => toDb ? 1 : 0,
fromDb => fromDb != 0);</bool></order>
同时在app.config中补上驱动映射(否则查询时仍可能出错):
<oracle.manageddataaccess.client><version number="*"><edmmappings><edmmapping datatype="number" precision="1" scale="0" name="boolean"></edmmapping></edmmappings></version></oracle.manageddataaccess.client>
注意:precision和scale必须与数据库列定义完全一致,多一位少一位都不触发映射。
最易被忽略的坑:NLS参数和隐式转换破坏映射一致性
即使你代码里写对了HasConversion,如果数据库会话的NLS_NUMERIC_CHARACTERS或NLS_TERRITORY设置异常,Oracle可能把NUMBER当字符串解析,导致EF Core收到的是string而非数值——这时HasConversion根本不会执行,直接抛InvalidCastException。
验证方法:连接数据库后立即执行SELECT * FROM NLS_SESSION_PARAMETERS WHERE PARAMETER IN ('NLS_NUMERIC_CHARACTERS', 'NLS_TERRITORY'),确保NLS_NUMERIC_CHARACTERS是'.,'(点作小数点,逗号作千分位),且NLS_TERRITORY不为'GERMANY'等会反转符号习惯的地区。











