2012-07-01 10 views
9

He encontrado el problema con el uso de tipo primitivo como un objeto @Id para JPA junto con Spring Data JPA. Tengo una relación de padre/hijo con Cascade.ALL en el lado de los padres, y el niño tiene PK, que al mismo tiempo también es FK de los padres.¿Utiliza siempre contenedores de objetos primitivos para JPA @Id en lugar de tipo primitivo?

class Parent { 
    @Id 
    private long id; 

    @OneToOne(mappedBy = "parent", cascade = ALL) 
    private Child child; 
} 

class Child { 
    @Id 
    @OneToOne 
    private Parent parent; 
} 

Así, cuando corro:

... 
Parent parent = new Parent(); 
Child child = new Child(parent); 
parent.setChild(child); 
em.persist(parent) 
... 

todo funciona bien. Pero solía primavera de datos JPA persistir la entidad, por lo que me quedo en su lugar:

parentRepository.save(parent); // instead of em.persist(parent); 

y éste ha fallado con la siguiente excepción:

Caused by: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: Parent 

El problema era que los datos de Primavera APP Guardar () método comprueba si la entidad es nueva, y si es nueva entonces se usa em.persist() de lo contrario em.merge() se utiliza.

La parte interesante aquí cómo cheques de primavera si la entidad no es nuevo o:

getId(entity) == null; 

Y, por supuesto, esto era falso, porque he usado siempre que el tipo de @Id, y el valor por defecto por mucho tiempo es 0. Cuando cambié de Long a Long todo funciona con Spring Data JPA también.

Por lo tanto, es la práctica recomendada utilizar siempre envoltorios de objetos para los tipos primitivos (como Largo en vez de largo) en lugar de tipos primitivos. Cualquier recurso de un tercero que describa esto como la práctica recomendada sería muy bueno.

+0

Gracias por compartir esta información con nosotros. –

+0

posible duplicado de [Primitiva o envoltura para claves primarias de hibernación] (http://stackoverflow.com/questions/3535791/primitive-or-wrapper-for-hibernate-primary-keys) – stevedbrown

Respuesta

12

Yo diría que sí, se recomienda usar tipos de objetos en lugar de primitivos debido al caso que está viendo. No hay forma de distinguir si la entidad es nueva o está preexistente con un identificador primitivo. He usado Hibernate durante años y siempre uso objetos para identificadores.

+1

+1, totalmente de acuerdo – Raman

0

Yo usaría un tipo de objeto. En el mapeo xml, podría poner un atributo de "valor no guardado", pero no creo que haya una traducción directa a las anotaciones para esto. Como resultado, es más seguro seguir con los tipos de objetos.

Y la mayoría de los programadores esperarían que un valor "nulo" en un identificador signifique no guardado de todos modos.

Cuestiones relacionadas