web-dev-qa-db-fra.com

Quand le JPA définit-il un @GeneratedValue @Id

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?

44
Raedwald

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.

21
Thomas

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.

11
JB Nizet

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éthode persist() 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.

8
Raedwald

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 et PostRemove 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éthodes PostPersist et PostRemove 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éthode PostPersist.

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 .

4
Jin Kwon