J'ai une entité JPA simple qui utilise un long
"ID" généré comme clé primaire:
@Entity
public class Player {
private long id;
protected Player() {
// Do nothing; id defaults to 0L
}
@GeneratedValue
@Id
public long getId() {
return id;
}
protected void setId(final long id) {
this.id = id;
}
// Other code
}
À un moment donné du cycle de vie d'un objet de ce type, le JPA doit appeler setId()
pour enregistrer la valeur d'ID générée. Ma question est, quand cela se produit-il, et où est la documentation qui le dit. J'ai parcouru la spécification JPA et je ne trouve pas de déclaration claire.
La spécification JPA dit (c'est moi qui souligne):
Une instance d'entité gérée est une instance avec un identité persistant qui est actuellement associé à un contexte de persistance.
Cela veut-il dire que l'objet doit être géré pour que son @Id
Soit significatif? La documentation de EntityManager.persist()
dit (non souligné dans l'original) qu'elle rend "une instance gérée et persistante", ce qui signifie que le @Id
Est défini par cette méthode? Ou n'est-ce pas jusqu'à ce que vous appeliez EntityTransaction.commit()
?
Lorsque @Id
Est défini, il peut être différent pour différents fournisseurs JPA et peut-être pour différentes stratégies de génération. Mais quelle est l'hypothèse la plus sûre (portable, conforme aux spécifications) que vous pouvez faire sur le premier point du cycle de vie qui a été défini?
appeler .persist () ne définira pas automatiquement la valeur id. Votre fournisseur JPA s'assurera qu'il est défini avant que l'entité ne soit finalement écrite dans db. Vous avez donc raison de supposer que l'ID sera attribué lorsque la transaction sera validée. Mais ce n'est pas le seul cas possible. Lorsque vous appelez .flush (), la même chose se produira.
Thomas
Mise à jour: faites attention au commentaire de Geek, s'il vous plaît. -> Si GenerationType.Identity est utilisé, l'ID ne sera pas défini par le fournisseur avant que l'entité ne soit écrite dans db. Dans ce cas, la génération d'ID se produit pendant le processus d'insertion au niveau de la base de données. Quoi qu'il en soit, le fournisseur JPA s'assurera que l'entité est mise à jour par la suite et que l'ID généré sera disponible dans la propriété annotée @Id.
AFAIK, l'ID ne peut être attribué que lorsque le contexte de persistance est vidé. Il peut être attribué plus tôt, mais cela dépend de la stratégie de génération.
Le livre Enterprise JavaBeans 3.1 de Rubinger et Burke dit ce qui suit, à la page 143 (non souligné dans l'original):
Java Persistence peut également être configuré pour générer automatiquement une clé primaire lorsque la méthode
persist()
est invoquée via l'utilisation de@GeneratedValue
Annotation au-dessus du champ de clé primaire ou du setter. Ainsi, dans l'exemple précédent, si la génération de clé automatique était activée, nous pourrions afficher la clé générée une fois la méthodepersist()
terminée.
La spécification JPA dit (c'est moi qui souligne):
Une instance d'entité gérée est une instance avec une identité persistante actuellement associée à un contexte de persistance.
Et aussi que EntityManager.persist()
fait
une instance gérée et persistante
Comme le @Id
Est crucial pour l'identité d'une entité, la seule façon pour EntityManager.persist()
de gérer l'objet est d'établir son identité en générant le @Id
.
Cependant
Rubinger et Buke la déclaration claire est incompatible avec le comportement d'Hibernate. Il semble donc que les personnes bien informées ne s'entendent pas sur l'intention de la spécification JPA.
Selon JSR 338: JavaTM Persistence 2.1 /3.5.3 Sémantique des méthodes de rappel du cycle de vie pour les entités ,
Les méthodes de rappel
PostPersist
etPostRemove
sont appelées pour une entité après que l'entité a été rendue persistante ou supprimée. Ces rappels seront également invoqués sur toutes les entités auxquelles ces opérations sont en cascade. Les méthodesPostPersist
etPostRemove
seront respectivement appelées après les opérations d'insertion et de suppression de base de données. Ces opérations de base de données peuvent se produire directement après que les opérations de persistance, de fusion ou de suppression ont été appelées ou elles peuvent se produire directement après qu'une opération de vidage s'est produite (ce qui peut être à la fin de la transaction). Les valeurs de clé primaire générées sont disponibles dans la méthodePostPersist
.
Une exception possible (présumée personnellement) est GeneratorType.TABLE
que le conteneur peut (peut) récupérer les valeurs à utiliser et (peut) le définir avant PrePersist
. J'utilise toujours mon id
dans PrePersist
. Je ne suis pas sûr que ce comportement soit spécifié ou peut ne pas fonctionner avec d'autres fournisseurs.
modification importante
Tous les serveurs d'applications ne définissent pas l'ID avant PrePersist
. Vous pouvez suivre JPA_SPEC .