You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF Core操作Oracle插入生成异常语句引发PLS-00510错误求助

问题描述

我在.NET 6环境中使用Entity Framework Core v7.0.11,搭配Oracle.EntityFrameworkCore v7.21.11和Oracle.ManagedDataAccess.Core v3.21.110 NuGet包,向Oracle的FRICTION表插入新数据时出现错误。

表结构

CREATE TABLE "xxx"."FRICTION" 
(   
    "TYPE" NUMBER(2,0) DEFAULT -1 NOT NULL ENABLE, 
    "V_MIN" FLOAT(25) DEFAULT 0 NOT NULL ENABLE, 
    "V_MAX" FLOAT(25) DEFAULT 0 NOT NULL ENABLE, 
    "ALPHA_MIN" FLOAT(25) DEFAULT 0 NOT NULL ENABLE, 
    "ALPHA_MAX" FLOAT(25) DEFAULT 0 NOT NULL ENABLE, 
    "MU_VMIN_ALPHAMIN" FLOAT(25) DEFAULT 0 NOT NULL ENABLE, 
    "MU_VMAX_ALPHAMIN" FLOAT(25) DEFAULT 0 NOT NULL ENABLE, 
    "EXP_ALPHAMIN" FLOAT(25) DEFAULT 0 NOT NULL ENABLE, 
    "MU_VMIN_ALPHAMAX" FLOAT(25) DEFAULT 0 NOT NULL ENABLE, 
    "MU_VMAX_ALPHAMAX" FLOAT(25) DEFAULT 0 NOT NULL ENABLE, 
    "EXP_ALPHAMAX" FLOAT(25) DEFAULT 0 NOT NULL ENABLE, 
    "OILED_MU_OFFSET" FLOAT(25) DEFAULT 0 NOT NULL ENABLE, 
    "WEAR_MAX_MU_OFFSET" FLOAT(25) DEFAULT 0.01 NOT NULL ENABLE, 
    "WEAR_MAX_MILEAGE" FLOAT(25) DEFAULT 150 NOT NULL ENABLE, 
    "WEAR_EXP" FLOAT(25) DEFAULT 25 NOT NULL ENABLE, 
    "ADA_RATE" FLOAT(25) DEFAULT 0.3 NOT NULL ENABLE, 
    "MIN_VMIN_ALPHAMIN" FLOAT(25) DEFAULT 0.045 NOT NULL ENABLE, 
    "MAX_VMIN_ALPHAMIN" FLOAT(25) DEFAULT 0.075 NOT NULL ENABLE, 
    "MIN_VMIN_ALPHAMAX" FLOAT(25) DEFAULT 0.065 NOT NULL ENABLE, 
    "MAX_VMIN_ALPHAMAX" FLOAT(25) DEFAULT 0.095 NOT NULL ENABLE, 
    "MIN_VMAX_ALPHAMIN" FLOAT(25) DEFAULT 0.025 NOT NULL ENABLE, 
    "MAX_VMAX_ALPHAMIN" FLOAT(25) DEFAULT 0.075 NOT NULL ENABLE, 
    "MIN_VMAX_ALPHAMAX" FLOAT(25) DEFAULT 0.065 NOT NULL ENABLE, 
    "MAX_VMAX_ALPHAMAX" FLOAT(25) DEFAULT 0.095 NOT NULL ENABLE
)

错误信息

ORA-06550: line 5, column 19:

PLS-00510: Float cannot have scale

EF Core生成的执行语句

DECLARE

TYPE "rFRICTION_0" IS RECORD
(
"OILED_MU_OFFSET" FLOAT(38,17)
);
TYPE "tFRICTION_0" IS TABLE OF "rFRICTION_0";
"lFRICTION_0" "tFRICTION_0";

BEGIN

"lFRICTION_0" := "tFRICTION_0"();
"lFRICTION_0".extend(1);
INSERT INTO "AMEH_RCM"."FRICTION" ("TYPE", "ADA_RATE", "ALPHA_MAX", "ALPHA_MIN", "EXP_ALPHAMAX", "EXP_ALPHAMIN", "MAX_VMAX_ALPHAMAX", "MAX_VMAX_ALPHAMIN", "MAX_VMIN_ALPHAMAX", "MAX_VMIN_ALPHAMIN", "MIN_VMAX_ALPHAMAX", "MIN_VMAX_ALPHAMIN", "MIN_VMIN_ALPHAMAX", "MIN_VMIN_ALPHAMIN", "MU_VMAX_ALPHAMAX", "MU_VMAX_ALPHAMIN", "MU_VMIN_ALPHAMAX", "MU_VMIN_ALPHAMIN", "V_MAX", "V_MIN", "WEAR_EXP", "WEAR_MAX_MILEAGE", "WEAR_MAX_MU_OFFSET")
VALUES (:p0, :p1, :p2, :p3, :p4, :p5, :p6, :p7, :p8, :p9, :p10, :p11, :p12, :p13, :p14, :p15, :p16, :p17, :p18, :p19, :p20, :p21, :p22)
RETURNING "OILED_MU_OFFSET" INTO "lFRICTION_0"(1)."OILED_MU_OFFSET";
OPEN :cur0 FOR SELECT "lFRICTION_0"(1)."OILED_MU_OFFSET" FROM DUAL;

END;

业务代码

var frictionEntity = new Friction
{
    Type = frictionSelectedItem.Type,
    VMin = frictionSelectedItem.VMin,
    VMax = frictionSelectedItem.VMax,
    AlphaMin = frictionSelectedItem.AlphaMin,
    AlphaMax = frictionSelectedItem.AlphaMax,
    MuVminAlphamin = frictionSelectedItem.MuVminAlphamin,
    MuVmaxAlphamin = frictionSelectedItem.MuVmaxAlphamin,
    ExpAlphamin = frictionSelectedItem.ExpAlphamin,
    MuVminAlphamax = frictionSelectedItem.MuVminAlphamax,
    MuVmaxAlphamax = frictionSelectedItem.MuVmaxAlphamax,
    ExpAlphamax = frictionSelectedItem.ExpAlphamax,
    OiledMuOffset = frictionSelectedItem.OiledMuOffset,
    WearMaxMuOffset = frictionSelectedItem.WearMaxMuOffset,
    WearMaxMileage = frictionSelectedItem.WearMaxMileage,
    WearExp = frictionSelectedItem.WearExp,
    AdaRate = frictionSelectedItem.AdaRate,
    MinVminAlphamin = frictionSelectedItem.MinVminAlphamin,
    MaxVminAlphamin = frictionSelectedItem.MaxVminAlphamin,
    MinVminAlphamax = frictionSelectedItem.MinVminAlphamax,
    MaxVminAlphamax = frictionSelectedItem.MaxVminAlphamax,
    MinVmaxAlphamin = frictionSelectedItem.MinVmaxAlphamin,
    MaxVmaxAlphamin = frictionSelectedItem.MaxVmaxAlphamin,
    MinVmaxAlphamax = frictionSelectedItem.MinVmaxAlphamax,
    MaxVmaxAlphamax = frictionSelectedItem.MaxVmaxAlphamax
};

context.Frictions.Add(frictionEntity);

context.SaveChanges();

更新:实体类与上下文配置

实体映射

[Table("FRICTION")]
public partial class Friction
{
    [Key]
    [Column("TYPE")]
    [Precision(2)]
    public int Type { get; set; }

    [Column("V_MIN", TypeName = "FLOAT")]
    public double VMin { get; set; }

    [Column("V_MAX", TypeName = "FLOAT")]
    public double VMax { get; set; }

    [Column("ALPHA_MIN", TypeName = "FLOAT")]
    public double AlphaMin { get; set; }

    [Column("ALPHA_MAX", TypeName = "FLOAT")]
    public double AlphaMax { get; set; }

    [Column("MU_VMIN_ALPHAMIN", TypeName = "FLOAT")]
    public double MuVminAlphamin { get; set; }

    [Column("MU_VMAX_ALPHAMIN", TypeName = "FLOAT")]
    public double MuVmaxAlphamin { get; set; }

    [Column("EXP_ALPHAMIN", TypeName = "FLOAT")]
    public double ExpAlphamin { get; set; }

    [Column("MU_VMIN_ALPHAMAX", TypeName = "FLOAT")]
    public double MuVminAlphamax { get; set; }

    [Column("MU_VMAX_ALPHAMAX", TypeName = "FLOAT")]
    public double MuVmaxAlphamax { get; set; }

    [Column("EXP_ALPHAMAX", TypeName = "FLOAT")]
    public double ExpAlphamax { get; set; }

    [Column("OILED_MU_OFFSET", TypeName = "FLOAT")]
    public double OiledMuOffset { get; set; }

    [Column("WEAR_MAX_MU_OFFSET", TypeName = "FLOAT")]
    public double WearMaxMuOffset { get; set; }

    [Column("WEAR_MAX_MILEAGE", TypeName = "FLOAT")]
    public double WearMaxMileage { get; set; }

    [Column("WEAR_EXP", TypeName = "FLOAT")]
    public double WearExp { get; set; }

    [Column("ADA_RATE", TypeName = "FLOAT")]
    public double AdaRate { get; set; }

    [Column("MIN_VMIN_ALPHAMIN", TypeName = "FLOAT")]
    public double MinVminAlphamin { get; set; }

    [Column("MAX_VMIN_ALPHAMIN", TypeName = "FLOAT")]
    public double MaxVminAlphamin { get; set; }

    [Column("MIN_VMIN_ALPHAMAX", TypeName = "FLOAT")]
    public double MinVminAlphamax { get; set; }

    [Column("MAX_VMIN_ALPHAMAX", TypeName = "FLOAT")]
    public double MaxVminAlphamax { get; set; }

    [Column("MIN_VMAX_ALPHAMIN", TypeName = "FLOAT")]
    public double MinVmaxAlphamin { get; set; }

    [Column("MAX_VMAX_ALPHAMIN", TypeName = "FLOAT")]
    public double MaxVmaxAlphamin { get; set; }

    [Column("MIN_VMAX_ALPHAMAX", TypeName = "FLOAT")]
    public double MinVmaxAlphamax { get; set; }

    [Column("MAX_VMAX_ALPHAMAX", TypeName = "FLOAT")]
    public double MaxVmaxAlphamax { get; set; }
}

DbContext的OnModelCreating配置

modelBuilder.Entity<Friction>(entity =>
{
    entity.HasKey(e => e.Type).HasName("FRICTION_PK");

    entity.Property(e => e.Type).HasDefaultValueSql("-1");
    entity.Property(e => e.AlphaMax).HasDefaultValueSql("0");
    entity.Property(e => e.AlphaMin).HasDefaultValueSql("0");
    entity.Property(e => e.ExpAlphamax).HasDefaultValueSql("0");
    entity.Property(e => e.ExpAlphamin).HasDefaultValueSql("0");
    entity.Property(e => e.MuVmaxAlphamax).HasDefaultValueSql("0");
    entity.Property(e => e.MuVmaxAlphamin).HasDefaultValueSql("0");
    entity.Property(e => e.MuVminAlphamax).HasDefaultValueSql("0");
    entity.Property(e => e.MuVminAlphamin).HasDefaultValueSql("0");
    entity.Property(e => e.OiledMuOffset).HasDefaultValueSql("0");
    entity.Property(e => e.VMax).HasDefaultValueSql("0");
    entity.Property(e => e.VMin).HasDefaultValueSql("0");
    entity.Property(e => e.WearExp).HasDefaultValueSql("25");
    entity.Property(e => e.WearMaxMileage).HasDefaultValueSql("150");
    entity.Property(e => e.WearMaxMuOffset).HasDefaultValueSql("0.01");
    entity.Property(e => e.AdaRate).HasDefaultValueSql("0.3");
    entity.Property(e => e.MinVminAlphamin).HasDefaultValueSql("0.045");
    entity.Property(e => e.MaxVminAlphamin).HasDefaultValueSql("0.075");
    entity.Property(e => e.MinVminAlphamax).HasDefaultValueSql("0.065");
    entity.Property(e => e.MaxVminAlphamax).HasDefaultValueSql("0.095");
    entity.Property(e => e.MinVmaxAlphamin).HasDefaultValueSql("0.025");
    entity.Property(e => e.MaxVmaxAlphamin).HasDefaultValueSql("0.075");
    entity.Property(e => e.MinVmaxAlphamax).HasDefaultValueSql("0.065");
    entity.Property(e => e.MaxVmaxAlphamax).HasDefaultValueSql("0.095");
});

核心疑问

为什么EF Core会生成带RETURNING的PL/SQL块,而不是单纯的INSERT语句?而且只有当OILED_MU_OFFSET为0时才会触发这个错误?


问题分析与解决方案

1. 生成RETURNING语句的原因

EF Core插入数据时,若实体属性配置了数据库默认值,且代码赋值与默认值相同,EF Core无法区分该值是手动设置还是数据库默认生成,会自动生成带RETURNING子句的PL/SQL块,将数据库实际存储的值回写到实体,保证内存与数据库数据一致。

具体到你的场景:

  • 当OILED_MU_OFFSET赋值为非0时,EF Core判断是手动赋值,直接生成普通INSERT;
  • 当赋值为0时,EF Core无法确认是否依赖数据库默认值,触发RETURNING逻辑,生成PL/SQL块同步数据。

2. 错误根源

Oracle的PL/SQL语法中,FLOAT类型不允许指定scale(小数位数),但当前版本的Oracle EF Core驱动错误地给FLOAT加上了(38,17)的精度和小数位数,导致Oracle抛出PLS-00510错误。这是驱动的版本兼容性问题。

3. 解决方案

方案一:匹配数据库类型定义

修改实体类中OILED_MU_OFFSET的TypeName为"FLOAT(25)",和数据库表定义一致:

[Column("OILED_MU_OFFSET", TypeName = "FLOAT(25)")]
public double OiledMuOffset { get; set; }

同时在OnModelCreating中同步配置:

entity.Property(e => e.OiledMuOffset)
    .HasDefaultValueSql("0")
    .HasColumnType("FLOAT(25)");

这样EF Core生成PL/SQL时会使用正确的FLOAT(25)类型,不会添加无效的scale参数。

方案二:禁用默认值回写

如果不需要EF Core同步数据库默认值到实体,可关闭该属性的默认值跟踪:

entity.Property(e => e.OiledMuOffset)
    .HasDefaultValueSql("0")
    .Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Ignore);

EF Core将不再生成RETURNING子句,直接使用普通INSERT语句。

方案三:升级驱动版本

该问题在Oracle.EntityFrameworkCore的更高版本中已修复,建议升级到最新稳定版(如v7.23.x及以上),避免驱动生成错误的PL/SQL类型定义。


内容的提问来源于stack exchange,提问作者dstreissi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 07:14:50