primary - jpa java entity
¿Cuándo establece el JPA un @GeneratedValue @Id (4)
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.
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 declaración 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?
De acuerdo con JSR 338: JavaTM Persistence 2.1 / 3.5.3 Semántica de los métodos de devolución de llamada del ciclo de vida para las entidades ,
Los métodos de devolución de llamada
PostPersist
yPostRemove
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étodosPostPersist
yPostRemove
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étodoPostPersist
.
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 .
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étodopersist()
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 declaración 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.
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.