¿Cuándo establece el JPA un @GeneratedValue @Id

Tengo una entidad JPA simple que usa una “ID” long generada como clave principal:

 @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 } 

En algún punto del ciclo de vida de un objeto de este tipo, el JPA debe llamar a setId() para registrar el valor de ID generado. Mi pregunta es, cuándo sucede esto, y dónde está la documentación que dice esto . Revisé la Especificación de JPA y no puedo encontrar una statement clara.

La especificación de JPA dice (énfasis añadido):

Una instancia de entidad gestionada es una instancia con una identidad persistente que está asociada actualmente a un contexto de persistencia.

¿ @Id está tratando de decir que el objeto debe ser administrado para que su @Id significativo? La documentación para EntityManager.persist() dice (énfasis agregado) que hace “una instancia gestionada y persistente”, ¿significa eso que @Id se establece con ese método? ¿O no será hasta que llame a EntityTransaction.commit() ?

Cuando se establece @Id puede ser diferente para diferentes proveedores de JPA, y quizás para diferentes estrategias de generación. Pero, ¿cuál es la suposición más segura (portátil, que cumpla con las especificaciones) que puede hacer sobre el primer punto en el ciclo de vida que se ha configurado?

Llamar .persist () no establecerá automáticamente el valor de identificación. Su proveedor de JPA se asegurará de que esté configurado antes de que la entidad finalmente se escriba en db. Por lo tanto, tiene razón al suponer que la identificación se asignará cuando se haya comprometido la transacción. Pero este no es el único caso posible. Cuando llamas a .flush (), pasará lo mismo.

Thomas

Actualización: presta atención al comentario de Geek, por favor. -> Si se utiliza GenerationType.Identity, el proveedor no establecerá la identificación antes de que la entidad se escriba en db. En este caso, la generación de id ocurre durante el proceso de inserción en el nivel de db. De todos modos, el proveedor de JPA se asegurará de que la entidad se actualice posteriormente y la identificación generada estará disponible en la propiedad @Id anotada.

AFAIK, la ID solo está garantizada para asignarse cuando se vacía el contexto de persistencia. Puede asignarse antes, pero depende de la estrategia de generación.

El libro Enterprise JavaBeans 3.1 de Rubinger and Burke dice lo siguiente, en la página 143 (énfasis añadido):

Java Persistence también se puede configurar para que genere automáticamente una clave principal cuando se invoca el método persist() mediante el uso de la anotación @GeneratedValue encima del campo de clave principal o del configurador. Entonces, en el ejemplo anterior, si teníamos habilitada la generación automática de claves, podríamos ver la clave generada después de que el método persist() completado.

La especificación de JPA dice (énfasis añadido):

Una instancia de entidad gestionada es una instancia con una identidad persistente que está asociada actualmente a un contexto de persistencia.

Y también que EntityManager.persist() hace

una instancia administrada y persistente

Como @Id es crucial para la identidad de una entidad, la única forma de que EntityManager.persist() haga que el objeto sea administrado es establecer su identidad generando el @Id .


sin embargo

La statement clara de Rubinger y Buke es inconsistente con el comportamiento de Hibernate. Por lo tanto, parece que la gente conocedora no está de acuerdo con lo que pretende la especificación JPA.

De acuerdo con JSR 338: JavaTM Persistence 2.1 / 3.5.3 Semántica de los métodos de callback del ciclo de vida para las entidades ,

Los métodos de callback PostPersist y PostRemove se invocan para una entidad después de que la entidad se haya vuelto persistente o eliminada. Estas devoluciones de llamada también se invocarán en todas las entidades a las que se conectan estas operaciones. Los métodos PostPersist y PostRemove se invocarán después de las operaciones de inserción y eliminación de la base de datos, respectivamente. Estas operaciones de base de datos pueden ocurrir directamente después de que se hayan invocado las operaciones de persistir, fusionar o eliminar, o pueden ocurrir directamente después de que haya ocurrido una operación de vaciado (que puede estar al final de la transacción). Los valores clave primarios generados están disponibles en el método PostPersist .

Una posible excepción (personalmente presumible) es GeneratorType.TABLE que el contenedor (puede) obtiene valores para usar y (puede) configurarlo antes de PrePersist . Siempre uso mi id en PrePersist . No estoy seguro de que se especifique este comportamiento o que no funcione con ningún otro proveedor.

edición importante

No todos los servidores de aplicaciones configuran id antes de PrePersist . Puede rastrear JPA_SPEC .