Hibernate注释多对一,不将子项添加到父集合

时间:2010-05-27 13:03:52

标签: java hibernate jpa many-to-one hibernate-annotations

我有以下带注释的Hibernate实体类:

@Entity
public class Cat {
    @Column(name = "ID") @GeneratedValue(strategy = GenerationType.AUTO) @Id
    private Long id;

    @OneToMany(mappedBy = "cat", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private Set<Kitten> kittens = new HashSet<Kitten>();

    public void setId(Long id) { this.id = id; }
    public Long getId() { return id; }
    public void setKittens(Set<Kitten> kittens) { this.kittens = kittens; }
    public Set<Kitten> getKittens() { return kittens; }
}

@Entity
public class Kitten {
    @Column(name = "ID") @GeneratedValue(strategy = GenerationType.AUTO) @Id
    private Long id;

    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private Cat cat;

    public void setId(Long id) { this.id = id; }
    public Long getId() { return id; }
    public void setCat(Cat cat) { this.cat = cat; }
    public Cat getCat() { return cat; }
}

我的意图是Cat和Kitten之间的双向一对多/多对一关系,其中Kitten是“拥有者”。

我想要发生的是当我创建一只新猫时,接着是一只引用猫的新小猫,我的猫上的小猫套装应该包含新的小猫。但是,在以下测试中,不会发生

@Test
public void testAssociations()
{
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    Transaction tx = session.beginTransaction();

    Cat cat = new Cat();
    session.save(cat);

    Kitten kitten = new Kitten();
    kitten.setCat(cat);
    session.save(kitten);

    tx.commit();

    assertNotNull(kitten.getCat());
    assertEquals(cat.getId(), kitten.getCat().getId());
    assertTrue(cat.getKittens().size() == 1); // <-- ASSERTION FAILS
    assertEquals(kitten, new ArrayList<Kitten>(cat.getKittens()).get(0));
}

即使在重新查询Cat之后,Set仍然是空的:

// added before tx.commit() and assertions
cat = (Cat)session.get(Cat.class, cat.getId());

我对Hibernate的期望过高吗?或者是我自己管理收藏品的负担? (Annotations) documentation没有表明我需要在父对象上创建便捷addTo* / removeFrom*方法。

有人可以告诉我Hibernate对这种关系的期望是什么吗?或者,如果没有别的,请指出正确的Hibernate文档,告诉我在这里应该发生什么。

我需要做些什么才能使父系列自动包含子实体?

2 个答案:

答案 0 :(得分:14)

它不会自动添加它。你必须自己添加它。

我也不会直接致电Kitten.setCat()。典型的模式是将方法放在Cat中:

public void addKitten(Kitten kitten) {
  if (kittens == null) {
    kittens = new HashSet<Kitten>();
  }
  kittens.add(kitten);
  kitten.setCat(this);
}

然后只需致电:

cat.addKitten(kitten);

答案 1 :(得分:3)

在处理双向关联时,您必须处理“链接”的两个方面,并且正如@cletus所建议的那样,使用防御性链接管理方法是很常见的。来自Hibernate Core文档:

  

1.2.6. Working bi-directional links

     

首先,请记住Hibernate   不会影响正常的Java语义。   我们是如何在a之间建立链接的?   人和事件在   单向的例子?你添加一个   事件的集合的集合   事件引用,实例的   人。如果你想建立这个链接   双向的,你必须这样做   在另一边添加一个相同的   人物参考集合   一个事件。这个过程“设定   双方的联系“绝对是   必要的双向链接。

     

许多开发人员都在防守计划   并创建链接管理方法   正确设置两侧(例如,   亲自):

protected Set getEvents() {
    return events;
}

protected void setEvents(Set events) {
    this.events = events;
}

public void addToEvent(Event event) {
    this.getEvents().add(event);
    event.getParticipants().add(this);
}

public void removeFromEvent(Event event) {
    this.getEvents().remove(event);
    event.getParticipants().remove(this);
}
     

获取和设置方法   收藏现在受到保护。这个   允许同一个包中的类和   子类仍然访问   方法,但防止其他人   从改变收藏品   直。重复上述步骤   收集在另一边。

更多参考资料