Как автоматически увеличить oracle таблицу из подхода Entity Framework, основанного на коде? - PullRequest
3 голосов
/ 04 августа 2020

У меня есть следующая таблица, в которой я только что добавил декоратор 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 19 c DB:

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 и вызовет ее из значения по умолчанию на следующем или что-то в этом роде. Но это не так.

Должен ли я теперь вручную создавать триггер и последовательность для каждого столбца?

Если да, то в чем смысл кода, если мне придется вмешиваться с самой базой данных.

Я не уверен, имеет ли это какой-либо эффект, но я настраиваю 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: Следуя этому руководству , я понял, что идентификатор класса модели (таблица) должен быть int, который равен числу (10, 0) в oracle условиях, чтобы автоматически создать желаемую последовательность (как столбец по умолчанию, вызывающий nextVal) на стороне БД.

Однако, глядя на миграцию вверх, похоже, нет никаких указаний создания этой последовательности, так что это просто наводит меня на мысль, что создание происходит где-то глубже и за пределами моей области знаний.

1 Ответ

2 голосов
/ 04 августа 2020

DatabaseGeneratedOption.Identity ожидает последовательность или столбец идентификаторов.

Столбцы идентификаторов поддерживаются начиная с версии 12 c, и на них не ссылаются ни триггеры, ни последовательности. Они обрабатываются внутри Oracle. Если вы получаете сообщение об ошибке

ORA-01400: невозможно вставить NULL

, это, вероятно, связано с тем, что вы делаете вставку без явного указания столбцов, или потому что вы используете неправильный тип IDENTITY, или потому что у вас нет последовательности.

У вас есть эти параметры для IDENTITY столбцов

  • GENERATED ALWAYS: Oracle всегда генерирует значение для столбца идентичности. Попытка вставить значение в столбец идентификаторов приведет к ошибке.
  • GENERATED BY DEFAULT: Oracle генерирует значение для столбца идентификаторов, если вы не указываете значение. Если вы укажете значение, Oracle вставит это значение в столбец идентификаторов. Для этого параметра Oracle выдаст ошибку, если вы вставите значение NULL в столбец идентификатора.
  • GENERATED BY DEFAULT ON NULL: Oracle генерирует значение для столбца идентификатора, если вы предоставите значение NULL или нет значение вообще.

Пример

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
...