EF Core 8 不支持 Oracle IDENTITY 列自动识别,需显式配置 ValueGeneratedOnAdd() 和 HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity),并确保表结构匹配(如用 GENERATED BY DEFAULT ON NULL AS IDENTITY),否则插入时触发 ORA-32795 或 ORA-01400 错误。

EF Core 8 不支持 Oracle IDENTITY 列的自动识别
EF Core 8 默认不会把 GENERATED ALWAYS AS IDENTITY 或 GENERATED BY DEFAULT AS IDENTITY 主键列当作自增字段处理——它会尝试插入 NULL 或默认值,结果触发 ORA-32795(ALWAYS)或 ORA-01400(BY DEFAULT 且未传值)错误。这不是 bug,而是 Oracle 的 IDENTITY 机制与 EF Core 的 Identity 假设不匹配:EF Core 认为“自增 = 插入时跳过该列”,但 Oracle 要求明确不提供该列(ALWAYS)或提供 NULL(BY DEFAULT ON NULL)才能触发序列。
必须显式配置 ValueGeneratedOnAdd + HasDatabaseGeneratedOption
要在 EF Core 8 中正确使用 Oracle 序列(无论底层是 IDENTITY 还是传统 Sequence+Trigger),关键不是靠“猜”,而是强制告诉 EF Core:“这个主键值由数据库生成,插入时不要发任何值”。
- 用
ValueGeneratedOnAdd()声明该属性在新增时由数据库生成 - 配合
HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)确保生成策略被正确定义(尤其在使用 Oracle Provider 8.x 时,仅靠ValueGeneratedOnAdd()可能不够) - 如果主键列名不是
Id(比如叫product_id),必须额外调用HasColumnName("product_id")
示例(OnModelCreating 中):
modelBuilder.Entity<product>()
.Property(p => p.Id)
.ValueGeneratedOnAdd()
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
.HasColumnName("product_id");</product>
Oracle 表结构必须匹配 EF Core 预期行为
EF Core 插入时不传主键列,所以你的 Oracle 表不能要求主键非空却没默认值或自增机制——否则直接报 ORA-01400。三种常见情况对应不同建表方式:
-
用 IDENTITY(推荐,Oracle 12c+):选
GENERATED BY DEFAULT ON NULL AS IDENTITY,它允许你 INSERT 时不提主键列,也允许传NULL,两者都触发自增;ALWAYS也行,但要求 EF Core 绝对不传该列(更严格) -
用 Sequence + Default(兼容老版本):建表时写
id NUMBER DEFAULT seq_product.nextval,这样即使 EF Core 某些路径误传了NULL,也能兜底生成值 -
用 Sequence + Trigger(不推荐):触发器里判断
:new.id IS NULL再赋值,但容易和 ORM 的并发插入逻辑冲突,且 EF Core 无法感知触发器行为,调试困难
MyBatis/MyBatis-Plus 用户注意:别混用注解和 EF Core 配置
如果你项目里同时存在 MyBatis 和 EF Core 访问同一张 Oracle 表,要小心注解污染。例如 MyBatis-Plus 的 @TableId(type = IdType.AUTO) 会让它自己去查 nextval,而 EF Core 又试图跳过主键列——两边逻辑打架,可能导致主键重复或跳号。统一用数据库侧机制(IDENTITY 或 DEFAULT)比 ORM 侧抢序列更可靠。
最易被忽略的一点:Oracle 的 CACHE 设置会影响主键连续性。哪怕只设 CACHE 20,数据库异常重启后可能丢失最多 20 个已分配但未使用的序列值——这在金融类业务中需提前对齐预期,不能假设“自增 = 绝对连续”。











