【问题标题】:Hibernate annotated many-to-one not adding child to parent CollectionHibernate注释多对一不将子添加到父集合
【发布时间】:2010-05-27 13:03:51
【问题描述】:

我有以下带注释的 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 文档,该文档告诉我我应该期待在这里发生什么。

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

【问题讨论】:

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


    【解决方案1】:

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

    我也不会直接打电话给Kitten.setCat()。典型的模式是在Cat 中放置一个方法,例如:

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

    然后简单地调用:

    cat.addKitten(kitten);
    

    【讨论】:

    • Hibernate 文档中是否有某个地方会告诉我这一点?我觉得(至少 Annotations 文档)在这方面有所欠缺。
    • @Rob 我发现 Hibernate 文档普遍缺乏。实际上,我对 EclipseLink 有更多的经验,它通常有更好的文档。另外,这本书非常值得投资amazon.com/Pro-JPA-Mastering-Persistence-Technology/dp/…(我有 JPA 1 的版本,非常棒,我想这也没什么不同)。
    • 感谢您的回答和书籍推荐。
    • 我也做了同样的事情,但没有改变。我有一个名为Artist 的抽象类,它是SingerBand 类的父类。我有一个相应的 artist_id 列作为外键,即使在应用您建议的更改后也没有设置。可能是什么问题?
    【解决方案2】:

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

    1.2.6. Working bi-directional links

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

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

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

    get 和 set 方法 收藏现在受到保护。这 允许在同一个包中的类和 子类仍然可以访问 方法,但阻止其他人 从改变收藏 直接地。重复上述步骤 在另一边收集。

    更多参考资料

    【讨论】:

    • 感谢您的链接; Hibernate 文档涵盖了相当多的内容,当您想知道特定事物(例如这样)时,似乎很难准确找到您正在寻找的内容。您提供的第一个链接几乎概括了我感兴趣的内容:“双向链接绝对需要这种‘在两侧设置链接’的过程。”
    • @Rob 我同意,确实,教程部分对此更加明确。以防万一,我认为 Bauer 的书 Java Persistence with Hibernate 是使用 Hibernate 时的必备伴侣(876 页!)。
    • 我不明白这是什么原因。
    猜你喜欢
    • 1970-01-01
    • 2015-08-20
    • 1970-01-01
    • 1970-01-01
    • 2014-09-07
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多