c# - 如何从实体框架代码优先方法自动增加 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)。
然而,看看向上迁移,似乎没有任何迹象表明这个序列的创造,所以它只是让我相信创造发生在我知识领域更深的地方。
解决方案
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
推荐阅读
- ruby-on-rails - Rails 将 user_id 从获取的 IP 地址分配给调查事件
- apache-spark - 尝试在 Windows 上运行 Apache Spark 示例时出错
- c# - Asp.Net Mvc 应用程序的 Redis 缓存实现
- javascript - 松露 - artifacts.require 不是函数
- c# - System.ServiceModel.Discovery 丢失?
- python-3.x - 为什么当我输入负整数时会有额外的“无”输出。我只期望“请输入正整数”输出
- html - html:5、html:xml、html5-boilerplate的解释
- mysql - 从日期列中获取最早的日期以在对另一列进行分组时显示
- sql - 使用 GROUP BY 和 COUNT 进行 SQL 选择?
- neo4j - 如何在 Neo4J 中实现日期时间数据