JPA @Id и insertable = false, updatable = false выбрасывает исключение


Я использую базу данных Oracle, и у меня есть последовательность и триггер для генерации и хранения ID перед вставкой.

CREATE SEQUENCE CASE_SEQ START WITH 1001 INCREMENT BY 1 NOMAXVALUE; 

CREATE OR REPLACE TRIGGER CASE_TR_SEQ
BEFORE INSERT ON CASE FOR EACH ROW
BEGIN
  SELECT CASE_SEQ.NEXTVAL INTO :NEW.CASE_ID FROM DUAL;
END;
/

Тогда у меня есть простая сущность со свойством:

@Id
@Column(name = "CASE_ID", insertable = false, updatable = false)
private Long caseId;

...когда я пытаюсь построить проект, я получаю:

Exception [EclipseLink-46] (Eclipse Persistence Services - 2.3.2.v20111125-r10461):
org.eclipse.persistence.exceptions.DescriptorException
Exception Description: There should be one non-read-only mapping defined for the
primary key field [CASE.CASE_ID].

Когда я удаляю вставляемое или обновляемое ключевое слово, это работает. Я знаю, что существует много решений, как генерировать ID с помощью JPA, также JPA может использовать (вызывать) последовательность oracle для установки (генерировать) ID. Но я стараюсь понять, почему это мои решения неправильный. Почему я не могу использовать оба ключевых слова вместе с аннотацией @Id? Моя мысль такова: я хочу запретить вставку или обновление caseId с помощью JPA.

1) Что такое правильное очищение души? Должен ли я использовать только @Id:
@Id
@Column(name = "CASE_ID")
private Long caseId;

Или лучше (безопаснее) определить insertable=false также:

@Id
@Column(name = "CASE_ID", insertable = false)
private Long caseId;

2) я понимаю, что updatable=false для @Id не имеет смысла (обновить первичный ключ не имеет смысла, но это возможно с помощью raw sql), но что это значит (у вас есть какой-то пример, когда это выгодно):

@Id
@Column(name = "CASE_ID", updatable = false)
private Long caseId;

EDIT 2012-04-13

Я сделал несколько тестов:

Сущность

@Id
@Column(name = "CASE_ID")
private Long caseId;

JPA log

INSERT INTO CASE (CASE_ID, CASE_DATE, INFO) VALUES (?, ?, ?)
bind => [3 parameters bound]|#]

Так что это небезопасно, потому что JPA пытается сохранить CASE_ID (который затем заменяется ID из последовательности Oracle триггером).

Сущность

@Id
@Column(name = "CASE_ID", insertable = false)
private Long caseId;

Создать метод

public void createCase(final Case caseData) {
    caseData.setCaseId(-1001L);
    em.persist(caseData);
}

JPA log

INSERT INTO CASE (CASE_DATE, INFO) VALUES (?, ?)
bind => [2 parameters bound]|#]

Это хорошо, потому что CASE_ID не является частью команды insert.

И обновление CASE_ID невозможно, потому что идентификатор аннотации:

public void update() {
    Case update = em.find(Case.class, 1023L);
    update.setCaseId(1028L);
}

Exception [EclipseLink-7251] (Eclipse Persistence Services - 2.3.2.v20111125-r10461):
org.eclipse.persistence.exceptions.ValidationException
Exception Description: The attribute [caseId] of class
[com.wordpress.kamiluv.jsfprototype.model.entity.Case] is mapped to a primary
key column in the database. Updates are not allowed.
Так что теперь последняя версия выглядит как самая безопасная, верно?
1 7

1 ответ:

В настоящее время вы говорите с вашими аннотациями JPA, что у вас есть столбец @Id, который никак не может быть вставлен или обновлен. Вы должны иметь возможность установить идентификатор перед вставкой или обновлением, но JPA не знает, как это сделать. Вам нужно будет использовать аннотацию @GeneratedValue на @Id, чтобы сообщить JPA, какую стратегию использовать (одну из: таблица,последовательность,идентичность,авто), если вы не хотите, чтобы идентификатор был установлен в вашем коде.