Я использую базу данных Oracle, и у меня есть последовательность и триггер для создания и сохранения идентификатора перед вставкой.
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].
Когда я удаляю либо вставляемое, либо обновляемое ключевое слово, тогда это работает. Я знаю, что существует множество решений, как сгенерировать идентификатор с помощью JPA, также JPA может использовать (вызывать) последовательность оракула для установки (сгенерированного) идентификатора. Но я пытаюсь понять, почему мои решения неверны. Почему я не могу использовать оба ключевых слова вместе с аннотацией @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) Я понимаю, что updateable=false для @Id не имеет значения (обновление первичного ключа не имеет значения, но оно возможно с помощью необработанного sql), но что это значит (у вас есть пример, когда это выгодно):
@Id
@Column(name = "CASE_ID", updatable = false)
private Long caseId;
Я провел несколько тестов:
Entity
@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 (который затем заменяется идентификатором из последовательности Oracle с помощью триггера).
Сущность
@Id
@Column(name = "CASE_ID", insertable = false)
private Long caseId;
Метод создания
public void createCase(final Case caseData) {
caseData.setCaseId(-1001L);
em.persist(caseData);
}
Журнал JPA
INSERT INTO CASE (CASE_DATE, INFO) VALUES (?, ?)
bind => [2 parameters bound]|#]
Это хорошо, потому что CASE_ID не является частью команды вставки.
И обновление CASE_ID невозможно, потому что 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.
Итак, теперь последняя версия выглядит как наиболее безопасная, верно?