7

映射双向列表时,我不了解 Hibernate 的行为。Hibernate 生成的 SQL 语句对我来说似乎不是最优的。有人可以启发我吗?

场景如下:我有一个一对多的父子关系。我将这种关系映射到一个双向列表。

根据Hibernate Annotation Reference Guide(章节:与索引集合的双向关联),映射应如下所示:

@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_idandparent_index似乎已经在第二个语句中设置。

当我更改映射并将属性“可更新=假,可插入=假”重复到父级中@JoinColumn的声明时,如下所示:

@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();

我正在使用休眠实体管理器 3.4.0.GA。

我错过了什么?Hibernate Reference Guide 不正确,还是我忽略了什么?

4

1 回答 1

6

好的,我没有足够彻底地阅读注释参考指南。

在第2.2.5.3.1.1 章中。双向明确说明:

要将双向一对多映射,将一对多作为拥有方,您必须删除 mappedBy 元素并将多对一 @JoinColumn 设置为可插入且可更新为 false。这个解决方案显然没有优化,并且会产生一些额外的 UPDATE 语句

在第 2.4.6.2.1 章中重复这些信息可能不会有什么坏处。与索引集合的双向关联

现在问题仍然存在:如果我在父级上重复@JoinColumn 属性“updatable = false”和“insertable = false”(请参阅​​第一篇文章中的代码),似乎不会产生额外的更新语句......这是一个合法的解决方法? 或者这会导致另一个问题吗?

于 2009-02-07T11:42:06.057 回答