我有以下带注释的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文档,告诉我在这里应该发生什么。
我需要做些什么才能使父系列自动包含子实体?
答案 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); }
获取和设置方法 收藏现在受到保护。这个 允许同一个包中的类和 子类仍然访问 方法,但防止其他人 从改变收藏品 直。重复上述步骤 收集在另一边。