ORA-01400 при попытке вставить в schema.table.ID

У меня есть таблица, в которой хранятся отклоненные предложения по контракту.

CREATE TABLE "STATUS_CONTRATO" (
  "STC_ID" NUMBER NOT NULL,
  "CTB_CONTRATO" NUMBER NOT NULL,
  "STC_DATA" DATE NOT NULL,
  "STC_OBSERVACAO" VARCHAR2(200) NOT NULL,
  CONSTRAINT "STATUS_CONTRATO_PK" 
    PRIMARY KEY ( "STC_ID") 
    ENABLE 
    VALIDATE,
  CONSTRAINT "FK_CONTRATO" 
    FOREIGN KEY ( "CTB_CONTRATO")
       REFERENCES "CONTRATO" ( CTB_CONTRATO) 
       ON DELETE SET NULL 
    ENABLE 
    VALIDATE)
;

(Сценарий, сгенерированный Visual Studio 2010)

Эта таблица имеет простой триггер, где значение STC_ID установлено:

TRIGGER "STATUS_CONTRATO_TRIGGER1"
  BEFORE
  INSERT
  ON "STATUS_CONTRATO"
  FOR EACH ROW

when (new.STC_ID = 0)
DECLARE
BEGIN 
  SELECT SEQ_STATUS_ID.NEXTVAL INTO :NEW.STC_ID FROM DUAL;
END;

SEQ_STATUS_ID это простая последовательность.

Вот моя проблема:

Я могу успешно выполнить эту вставку в окне запроса VS2010:

insert into myschema.STATUS_CONTRATO s(
  s.STC_ID, s.CTB_CONTRATO, s.STC_DATA, s.STC_OBSERVACAO
)values(
  0, 10, SYSDATE, 'Inserting by hand works'
);

Но, когда я пытаюсь вставить, используя EF, я получаю это исключение:

System.Data.UpdateException: An error occurred while updating the entries. 
See the inner exception for details. ---> Oracle.DataAccess.Client.OracleException: 
ORA-01400: cannot insert NULL into ("MYSCHEMA"."STATUS_CONTRATO"."STC_ID")
ORA-06512: at line 4

Я использую этот код для вставки

STATUS_CONTRATO statusContrato = new STATUS_CONTRATO() {
    STC_ID = 0,
    CTB_CONTRATO = codContrato,
    STC_DATA = DateTime.Today,
    STC_OBSERVACAO = observacao
};
ent.STATUS_CONTRATO.AddObject(statusContrato);
ent.SaveChanges();

Я использую VS2010, Oracle 11g (CentOS Server), клиент ODP.NET 11.2.0.3.0 Production, .NET Framework 4.0, EF 4.

3 ответа

Решение

Проверьте это: http://www.oracle.com/technetwork/issue-archive/2011/11-sep/o51odt-453447.html

В частности, раздел "Триггеры и последовательности"

В меню "Сервис" выберите "Запустить сценарий SQL Plus". Перейдите в папку, в которую вы распаковали код и сценарии, выберите сценарий triggers.sql, выберите соединение HR из списка и нажмите "Выполнить". Триггер INSERTEMPLOYEES, созданный сценарием, генерирует новую последовательность для EMPLOYEE_ID всякий раз, когда для этого значения передается NULL........

Ваш код работает, за исключением проблемы с

ent.UNV_STATUS_CONTRATO.AddObject(statusContrato);

Является UNV_STATUS_CONTRATO другой стол? Почему нет

ent.STATUS_CONTRATO.AddObject(statusContrato);

Это должно работать просто отлично.

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

    public static int GetSequenceNextVal()
    {
        using (YourEntities entities = new YourEntities ())
        {
            var sql = "select myschema.SEQ_STATUS_ID.NEXTVAL from dual";
            var qry = entities.ExecuteStoreQuery<decimal>(sql);
            return (int)qry.First();
        }
    }

Затем вы вызываете этот метод до SaveChanges(),

Лично я предпочитаю обрабатывать это таким образом, чтобы моя сущность в памяти также имела правильный идентификатор, вместо того, чтобы просто иметь 0, или запрашивать его обратно и т. Д.

Кроме того, метод, описанный здесь в разделе "Триггеры и последовательности", может предположительно связать PK объекта с последовательностью.

Вы должны указать в своем EF Mapping, что БД не генерирует ключ для вас, и EF должен использовать ключ, который вы предоставили...

см. мой пост в следующей теме: /questions/42687944/poluchenie-nevozmozhno-vstavit-null-v-shema-tablitsa-stolbets-kogda-stolbets-ne-raven-null/42687956#42687956

Другие вопросы по тегам