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?