2012-01-31 11 views
36

Tengo una simple entidad JPA que utiliza un generada long "ID" como su clave principal:establecer la APP un @GeneratedValue @Id

@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 un cierto punto en el ciclo de vida de un objeto de este tipo, el JPA debe llamar al setId() para registrar el valor de ID generado. Mi pregunta es, cuando sucede esto, y donde está la documentación que dice esto. Revisé la Especificación de JPA y no puedo encontrar una declaración clara.

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

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

es que intentar decir que el objeto debe ser administrado a tener su @Id significativa? La documentación para EntityManager.persist() dice (énfasis añadido) hace "una instancia administrada y persistente", ¿significa eso que el @Id está establecido por ese método? ¿O no será hasta que llame al 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?

+0

Parece algo que podría establecerse fácilmente con la depuración. – skaffman

+3

Apuesto a que si las especificaciones no dicen explícitamente * cuándo * se debe generar el @Id, entonces los proveedores deben decidirlo. –

+0

@Raedwald: la depuración le dirá cómo funciona JPA internamente, y le dirá qué bits son específicos del dialecto. – skaffman

Respuesta

19

llamando .persist() no establecerá automáticamente el valor de id. 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: prestar 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.

+1

Suena razonable. Entonces, si llama a 'EntityManager.flush()' ¿puede confiar en que se haya establecido '@ Generated'' @ Id'? No puedo encontrar pistas en la documentación. – Raedwald

+1

También puede consultar esta publicación en el foro de hibernación: https://forum.hibernate.org/viewtopic.php?p=2384011#p2384011 Parece depender de la estrategia del generador elegido – Thomas

+1

De acuerdo con la documentación de EntityManager http : //docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html#flush() flush "Sincronizará el contexto de persistencia a la base de datos subyacente". Esto significa que todas las instrucciones de inserción agrupadas se escribirán en db para sincronizar el estado. Para hacerlo, su proveedor de JPA necesita esos valores de id. Entonces deberían estar disponibles después de llamar al color. Sin embargo, algunas estrategias podrían establecerlos antes. – Thomas

11

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.

7

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

persistencia de Java también puede ser configurado para generar automáticamente una clave principal cuando el método persist() se invoca mediante el uso de la anotación @GeneratedValue en la parte superior del campo de clave principal o del colocador. Por lo tanto, en el ejemplo anterior, si teníamos habilitada la generación automática de claves, podríamos ver la clave generada después de completar el método persist().

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

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

Y también que EntityManager.persist() hace

una instancia administrada y persistente

A medida que el @Id es crucial para el identidad de una entidad, la única manera para EntityManager.persist() para hacer el objeto gestionado es establecer su identidad generando el @Id.


Sin embargo

Rubinger y declaración clara de Buke es incompatible 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.

4

Según JSR 338: JavaTM Persistence 2.1/3.5.3 Semántica del ciclo de métodos de devolución de llamada de vida para Entidades,

Los PostPersist y PostRemove métodos de devolución de llamada se invocan para una entidad después de la entidad se ha hecho persistente o eliminado. 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 e 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 de clave primaria generados están disponibles en el método PostPersist.

Una posible (personalmente presumible) excepción es GeneratorType.TABLE la que el recipiente (mayo) obtiene los valores a utilizar y (pueden) configurarlo antes 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.

importante edición

No todos los servidores de aplicaciones antes de programar una ID PrePersist. Puede rastrear JPA_SPEC.

+0

Buen punto. Lamentablemente, cualquiera está votando. – Gilberto

Cuestiones relacionadas