I am using an Oracle database and I have a sequence and trigger to generate and store the identifier before insertion.
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; /
Then I have a simple object with the property:
@Id @Column(name = "CASE_ID", insertable = false, updatable = false) private Long caseId;
... when I try to build a project, I get:
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].
When I delete either the inserted or updated keyword, it works. I know that there are many solutions how to generate an identifier using JPA, and JPA can use (invoke) the oracle sequence to set the (generated) identifier. But I'm trying to understand why my decisions are wrong. Why can't I use both keywords with the @Id annotation? My thought is this: I want to prevent the insert or update of caseId using JPA.
1) What is the right soul? Should I use only @Id:
@Id @Column(name = "CASE_ID") private Long caseId;
or better (safer) define insertable = false also:
@Id @Column(name = "CASE_ID", insertable = false) private Long caseId;
2) I understand that updatable = false for @Id does not make sense (updating the Primary Key does not make sense, but this is possible using raw sql), but what does it mean (you have an example when it is useful):
@Id @Column(name = "CASE_ID", updatable = false) private Long caseId;
EDIT 2012-04-13
I did some tests:
An object
@Id @Column(name = "CASE_ID") private Long caseId;
Jpa log
INSERT INTO CASE (CASE_ID, CASE_DATE, INFO) VALUES (?, ?, ?) bind => [3 parameters bound]|
So, this is unsafe because the JPA is trying to store the CASE_ID (which is then replaced with the identifier from the Oracle sequence by a trigger).
An object
@Id @Column(name = "CASE_ID", insertable = false) private Long caseId;
Create method
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]|
This is good because CASE_ID is not part of the insert command.
And updating CASE_ID is not possible because annotation 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.
So now the latest version looks like the safest, right?