2012-04-12 2 views
7

J'utilise la base de données Oracle et j'ai une séquence et un déclencheur pour générer et stocker l'ID avant l'insertion.JPA @Id et insertable = false, updatable = false jette l'exception

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; 
/

Ensuite, je dois entité simple avec la propriété:

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

... lorsque je tente construire des projets que je reçois:

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

Lorsque je supprimer soit mot-clé insérable ou actualisable , alors ça marche. Je sais qu'il y a beaucoup de solutions pour générer des ID en utilisant JPA, et JPA peut aussi utiliser (call) une séquence oracle pour définir des ID (générés). Mais j'essaie de comprendre pourquoi mes solutions sont fausses. Pourquoi je ne peux pas utiliser les deux mots clés avec l'annotation @Id? Ma pensée est la suivante: Je veux interdire l'insertion ou la mise à jour de caseId par JPA.

1) Quelle est la bonne soulution? Dois-je utiliser seulement @Id:

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

ou est meilleure (plus sûr) insérable = false définir aussi:

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

2) Je comprends que actualisable = false pour @Id n'a pas de sens (mise à jour clé primaire n'a pas de signification, mais il est possible par sql cru), mais qu'est-ce que cela veut dire (avez-vous quelques exemples quand il est bénéfique):

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

EDIT 2012-04-13

J'ai fait quelques tests:

Entité

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

JPA log

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

Donc, ce n'est pas sûr, parce que JPA essaie magasin CASE_ID (qui est ensuite remplacé par ID de la séquence Oracle par déclencheur).

Entité

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

Créer méthode

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]|#] 

Il est bon, parce que le CASE_ID ne fait pas partie de la commande d'insertion.

et mise à jour de CASE_ID n'est pas possible parce que l'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. 

Alors maintenant, la dernière version se présente comme le plus sûr, non?

+1

Jetez un oeil à http://stackoverflow.com/questions/3669883/hibernate-where-do-insertable-false-updatable-false-belong-in-composite-pr et http://stackoverflow.com/questions/3805584/please-explain-about-insertable-false-updatable-false et voyez si cela vous aide. –

+0

@tech_learner malheureusement pas beaucoup – Ziletka

+1

Je ne suis pas sûr, si cela aide, mais vous cherchez une classe immuable? Si oui, jetez un oeil à ceci: http://www.mkyong.com/hibernate/hibernate-mutable-example-class-and-collection/ –

Répondre

5

Vous dites actuellement avec vos annotations JPA que vous avez une colonne @Id qui ne peut être insérée ou mise à jour d'aucune façon. Vous devez être en mesure de définir l'identifiant avant de l'insérer ou de le mettre à jour, mais JPA ne sait pas comment le faire.Vous devrez utiliser l'annotation @GeneratedValue sur l'ID @ pour indiquer à JPA la stratégie à utiliser (l'une des suivantes: TABLE, SEQUENCE, IDENTITY, AUTO) si vous ne souhaitez pas que l'ID soit défini dans votre code.

+0

Ok, mais je ne veux pas utiliser les possibilités de '@GeneratedValue' , J'aimerais utiliser le déclencheur Oracle pour définir l'ID dans les colonnes de la base de données. Et supprimer '@Id' n'est pas une bonne solution car il y a quelques fonctionnalités connectées avec '@Id' dans JPA, par exemple: EntityManager find (Case.class, caseId). – Ziletka

+0

Si vous souhaitez utiliser un déclencheur Oracle, essayez @GeneratorValue (strategy = GenerationType.AUTO). Je ne suis pas sûr d'Oracle, mais j'ai réussi avec AUTO sur une table Sybase qui gérait la génération d'ID elle-même. – bobz32

+0

cela fonctionne mais je pense que ce n'est pas de bonnes solutions, la stratégie bacuase ATUTO est définie pour une signification différente ... DOC: Spécifier une stratégie de AUTO permet à EclipseLink de sélectionner la stratégie à utiliser. En règle générale, EclipseLink choisit TABLE comme stratégie, car c'est la stratégie la plus portable. Toutefois, lorsque AUTO est spécifié, la génération de schéma doit être utilisée au moins une fois pour que la table par défaut soit créée dans la base de données. – Ziletka

Questions connexes