首页 > 解决方案 > 如何从实体框架代码优先方法自动增加 oracle 表?

问题描述

我有下表,我刚刚添加了装饰器,DatabaseGenerated如下所示:

public class Reference
{
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        [Key]
        public decimal ReferenceId { get; set; }
        public string AddressType { get; set; }
        public string RefferenceType { get; set; }
        public string RefferenceValue { get; set; }
        [ForeignKey("Shipment")]
        public decimal? TrackingNumber { get; set; }
        public Shipment Shipment { get; set; }
}

我最新推送到 oracle 19c 数据库的向上迁移是:

public override void Up()
{
    DropPrimaryKey("SALOGSEARCH.References");
    AlterColumn("SALOGSEARCH.References", "ReferenceId", c => c.Decimal(nullable: false, precision: 20, scale: 0, identity: true));
    AddPrimaryKey("SALOGSEARCH.References", "ReferenceId");
}

然而,当我在添加后执行我的上下文保存时:

using (var context = new DbContext())
{
    context.Reference.Add(shipperReference);
    context.SaveChanges();
}

我得到一个例外

ORA-01400: 无法插入 NULL

我假设该标签DatabaseGeneratedOption.Identity会在 Oracle 数据库中生成一个序列,并从 next 或其他东西的默认值中调用它。但事实并非如此。

我现在是否必须为每列手动创建触发器和序列?

如果是这样,那么如果我必须自己干预数据库,那么代码的意义何在。

我不确定这是否有任何影响,但我正在调整OnModelCreating如下:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.HasDefaultSchema("SALOGSEARCH");

    modelBuilder.Properties<string>().Configure(s => s.HasMaxLength(400).HasColumnType("Varchar2"));
    modelBuilder.Properties<decimal>().Configure(s => s.HasPrecision(20, 0).HasColumnType("Number"));
}

任何从 c# 方面解决此问题的指针将不胜感激。

EDIT1:按照本教程,我开始意识到模型类(表)的 Id 需要是一个 int,在 oracle 术语中它是 number(10, 0) 以便自动创建所需的序列(作为列默认值在数据库端调用 nextVal)。

然而,看看向上迁移,似乎没有任何迹象表明这个序列的创造,所以它只是让我相信创造发生在我知识领域更深的地方。

标签: c#oracleentity-framework-6oracle19c

解决方案


DatabaseGeneratedOption.Identity需要一个序列或一个标识列。

自版本 12c 起支持标识列,触发器和序列均未引用该列。它们由 Oracle 内部处理。如果你得到一个错误

ORA-01400: 无法插入 NULL

这可能是因为您在没有明确命名列的情况下进行插入,或者因为您使用了错误的 IDENTITY 类型,或者因为您没有序列。

您有这些IDENTITY列选项

  • GENERATED ALWAYS:Oracle 总是为标识列生成一个值。尝试将值插入标识列将导致错误。
  • GENERATED BY DEFAULT:如果您不提供值,Oracle 会为标识列生成一个值。如果您提供一个值,Oracle 会将该值插入到标识列中。对于此选项,如果您将 NULL 值插入标识列,Oracle 将发出错误。
  • GENERATED BY DEFAULT ON NULL:如果您提供 NULL 值或根本不提供值,Oracle 会为标识列生成一个值。

例子

SQL> create table t ( c1 number generated  by default as identity ( start with 1 increment by 1 ) , c2 number ) ;

Table created.

SQL> insert into t ( c2 ) values ( 1 ) ;

1 row created.

SQL> select * from t ;

        C1         C2
---------- ----------
         1          1

SQL>  insert into t ( c1 , c2 ) values ( null , 1 ) ;
 insert into t ( c1 , c2 ) values ( null , 1 )
                                    *

第 1 行的错误:
ORA-01400:无法将 NULL 插入 ("MY_SCHEMA"."T"."C1")

但是我可以进行插入并明确引用 IDENTITY

SQL>  insert into t ( c1, c2 ) values ( 2, 2 ) ;

1 row created.

SQL> select * from t ;

        C1         C2
---------- ----------
         1          1
         2          2

SQL> insert into t ( c2 ) values ( 3 ) ;

1 row created.

SQL> select * from t ;

        C1         C2
---------- ----------
         1          1
         2          2
         2          3

在你的情况下,我会使用GENERATED BY DEFAULT ON NULL

SQL> create table t ( c1 number generated by default on null as identity ( start with 

1 increment by 1 ) , c2 number ) ;

Table created.

SQL>  insert into t values ( null , 1 ) ;

1 row created.

SQL> select * from t ;

        C1         C2
---------- ----------
         1          1

推荐阅读