2009-02-02 11 views
7

No entiendo el comportamiento de Hibernate al mapear una lista bidireccional. Las sentencias SQL que produce Hibernate no me parecen óptimas. ¿Alguien puede iluminarme?Asignación de una lista bidireccional con Hibernate

El escenario es el siguiente: Tengo una relación uno a varios entre padres e hijos. Mapeo esta relación con una lista bidireccional.

De acuerdo con la Hibernate Annotation Reference Guide (Capítulo: asociación bidireccional con colecciones indexadas) el mapeo debe tener este aspecto:

@Entity 
public class Parent { 

    @Id @GeneratedValue private long id; 
    @Version private int version; 
    private String name; 

    @OneToMany(cascade = CascadeType.ALL) 
    @JoinColumn(name = "parent_id", nullable=false) 
    @org.hibernate.annotations.IndexColumn(name = "parent_index") 
    List<Child> children = new ArrayList<Child>(); 

... 

@Entity 
public class Child { 

    @Id @GeneratedValue private Long id; 
    @Version private int version; 
    private String name; 

    @ManyToOne 
    @JoinColumn(name = "parent_id", updatable = false, insertable = false, nullable=false) 
    private Parent parent; 

... 

Pero en este caso Hibernate produce tres sentencias SQL cuando persisten un padre con un hijo:

Hibernate: insert into Parent (name, version, id) values (?, ?, ?) 
Hibernate: insert into Child (name, price, version, parent_id, parent_index, id) values (?, ?, ?, ?, ?, ?) 
Hibernate: update Child set parent_id=?, parent_index=? where id=? 

La tercera instrucción parece ser redundante, porque parent_id y parent_index parecen estar ya establecidos en la segunda instrucción.

Cuando cambio el mapeo y repetir los atributos 'actualizable = false, insertable = false' a la declaración de la @JoinColumn en el Padre así:

@Entity 
public class Parent { 

    @Id @GeneratedValue private long id; 
    @Version private int version; 
    private String name; 

    @OneToMany(cascade = CascadeType.ALL) 
    @JoinColumn(name = "parent_id", updatable = false, insertable = false, nullable=false) 
    @org.hibernate.annotations.IndexColumn(name = "parent_index") 
    List<Child> children = new ArrayList<Child>(); 

... 

@Entity 
public class Child { 

    @Id @GeneratedValue private Long id; 
    @Version private int version; 
    private String name; 

    @ManyToOne 
    @JoinColumn(name = "parent_id", updatable = false, insertable = false, nullable=false) 
    private Parent parent; 

... 

... entonces Hibernate parece producir SQL mucho más optimizado:

Hibernate: insert into Parent (name, version, id) values (?, ?, ?) 
Hibernate: insert into Child (name, price, version, parent_id, parent_index, id) values (?, ?, ?, ?, ?, ?) 

El código de cliente es el siguiente:

EntityManagerFactory emf = Persistence.createEntityManagerFactory("test"); 
    EntityManager em = emf.createEntityManager(); 
    EntityTransaction tx = em.getTransaction(); 
    tx.begin(); 

    Parent newParent = new Parent(); 
    newParent.setName("Parent1"); 

    Child newChild = new Child(); 
    newChild.setName("Child1"); 

    newParent.getChildren().add(newChild); 
    newChild.setParent(newParent); 

    em.persist(newParent); 

    em.flush(); 
    tx.commit(); 

Estoy usando hibernate-entitymanager 3.4.0.GA.

¿Qué me estoy perdiendo? ¿La Guía de referencia de Hibernate no es correcta o estoy pasando por alto algo?

Respuesta

6

Ok, no estaba leyendo la Guía de referencia de anotaciones lo suficiente.

En el capítulo 2.2.5.3.1.1. Bidirectional se afirma claramente:

Para asignar un ser bidireccional para muchos, con la cara de uno-a-muchos como el lado propietario, usted tiene que quitar el elemento mappedBy y establecer el muchos a uno @JoinColumn como insertable y actualizable a falso. Esta solución obviamente no está optimizada y producirá algunas declaraciones de ACTUALIZACIÓN adicionales.

Probablemente no estaría de más repetir esta información en Chapter 2.4.6.2.1. Bidirectional association with indexed collections.

Ahora queda la pregunta: si repito los atributos @JoinColumn 'updatable = false' e 'insertable = false' en Parent (vea el código en la primera publicación) las sentencias de actualización adicionales parecen no producirse ... es esta es una solución legítima? ¿O esto resulta en otro problema?

Cuestiones relacionadas