Я не понимаю поведение Hibernate при отображении двунаправленного списка. Операторы SQL, которые создает Hibernate, кажутся мне неоптимальными. Может ли кто-нибудь просветить меня?
Сценарий следующий: у меня отношения один-ко-многим родитель-ребенок. Я сопоставляю эти отношения с двунаправленным списком.
В соответствии с Справочным руководством по Hibernate (Глава: Двунаправленная связь с индексированными коллекциями) отображение должно выглядеть следующим образом:
@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;
...
Но в этом случае Hibernate создает три оператора SQL при сохранении родителя с одним дочерним элементом:
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=?
Третье утверждение представляется излишним, поскольку parent_id
и parent_index
, похоже, уже заданы во втором утверждении.
Когда я изменяю отображение и повторяю атрибуты ' updatable = false, вставляемый = false ' для объявления @ JoinColumn в Parent следующим образом:
@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;
...
... тогда Hibernate производит гораздо более оптимизированный SQL:
Hibernate: insert into Parent (name, version, id) values (?, ?, ?)
Hibernate: insert into Child (name, price, version, parent_id, parent_index, id) values (?, ?, ?, ?, ?, ?)
Код клиента выглядит следующим образом:
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();
Я использую hibernate-entitymanager 3.4.0.GA.
Что мне не хватает? Справочное руководство по Hibernate неверно или я что-то упускаю?