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

发布于 2024-09-02 20:18:33 字数 2251 浏览 11 评论 0原文

我有以下带注释的 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 的期望是否过高?或者我有责任自己管理馆藏? (注释)文档不会做任何指示我需要在父对象上创建便捷的 addTo*/removeFrom* 方法。

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

我需要做什么才能使父集合自动包含子实体?

I have the following annotated Hibernate entity classes:

@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; }
}

My intention here is a bidirectional one-to-many/many-to-one relationship between Cat and Kitten, with Kitten being the "owning side".

What I want to happen is when I create a new Cat, followed by a new Kitten referencing the Cat, the Set of kittens on my Cat should contain the new Kitten. However, this does not happen in the following test:

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

Even after re-querying the Cat, the Set is still empty:

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

Am I expecting too much from Hibernate here? Or is the burden on me to manage the Collection myself? The (Annotations) documentation doesn't make any indication that I need to create convenience addTo*/removeFrom* methods on my parent object.

Can someone please enlighten me on what my expectations should be from Hibernate with this relationship? Or if nothing else, point me to the correct Hibernate documentation that tells me what I should be expecting to happen here.

What do I need to do to make the parent Collection automatically contain the child Entity?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

是伱的 2024-09-09 20:18:33

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

我也不会直接调用 Kitten.setCat() 。典型的模式是将一个方法放入 Cat 中,例如:

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

然后简单地调用:

cat.addKitten(kitten);

It won't automatically add it. You have to add it yourself.

I wouldn't directly call Kitten.setCat() either. The typical pattern for this is to put a method in Cat like:

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

and then simply call:

cat.addKitten(kitten);
七色彩虹 2024-09-09 20:18:33

当使用双向关联时,您必须处理“链接”的两侧,并且为此使用防御性链接管理方法是很常见的,正如 @cletus 所建议的。来自 Hibernate 核心文档:

1.2.6 。工作双向链接

首先,请记住 Hibernate
不影响正常的Java语义。
我们如何在
中的人物和事件
单向的例子?您添加一个
事件的实例到集合
实例的事件引用
人。如果你想建立这个链接
双向,你必须做
另一边也一样,添加一个
人员对集合的引用
一个事件。这个“设置
双方的链接”绝对是
双向链接所必需的。

许多开发人员进行防御性编程
并创建链接管理方法
正确设置两侧(例如,
亲自):

protected Set getEvents() {
    返回事件;
}

protected void setEvents(设置事件) {
    this.events = 事件;
}

公共无效addToEvent(事件事件){
    this.getEvents().add(事件);
    event.getParticipants().add(this);
}

公共无效removeFromEvent(事件事件){
    this.getEvents().remove(事件);
    event.getParticipants().remove(this);
}

获取和设置方法
收藏现已受到保护。这
允许类在同一个包中并且
子类仍然可以访问
方法,但阻止了其他人
改变集合
直接地。重复以下步骤
另一边收集。

更多参考

When working with bi-directional associations, you have to handle both sides of the "link" and it is very common to use defensive link management methods for that, as suggested by @cletus. From Hibernate Core documentation:

1.2.6. Working bi-directional links

First, keep in mind that Hibernate
does not affect normal Java semantics.
How did we create a link between a
Person and an Event in the
unidirectional example? You add an
instance of Event to the collection of
event references, of an instance of
Person. If you want to make this link
bi-directional, you have to do the
same on the other side by adding a
Person reference to the collection in
an Event. This process of "setting
the link on both sides" is absolutely
necessary with bi-directional links.

Many developers program defensively
and create link management methods to
correctly set both sides (for example,
in Person):

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);
}

The get and set methods for the
collection are now protected. This
allows classes in the same package and
subclasses to still access the
methods, but prevents everybody else
from altering the collections
directly. Repeat the steps for the
collection on the other side.

More References

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文