代码之家  ›  专栏  ›  技术社区  ›  Rob Hruska MegalomanINA

休眠注释多对一,不向父集合添加子集合

  •  6
  • Rob Hruska MegalomanINA  · 技术社区  · 14 年前

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

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

    我的目的是在猫和小猫之间建立一种双向的一对多/多对一的关系,小猫是“拥有方”。

    我想发生的是当我创建一只新的猫,然后是一只新的小猫引用猫, 我猫上的那套小猫应该包括新来的小猫 . 然而,这 不会发生 在以下测试中:

    @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之后,集合仍为空:

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

    我对冬眠的期望太高了吗?或者是我自己管理收藏品的负担?这个 (Annotations) documentation 没有任何迹象表明我需要创造便利 addTo* / removeFrom* 方法。

    有人能告诉我,我对这段关系的期望是什么?或者,如果没有其他内容,请指向正确的Hibernate文档,该文档告诉我在这里应该发生什么。

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

    2 回复  |  直到 14 年前
        1
  •  14
  •   cletus    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);
    
        2
  •  3
  •   Pascal Thivent    14 年前

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

    1.2.6. Working bi-directional links

    首先,记住冬眠 不影响正常的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方法 集合现在受保护。这个 允许同一包中的类,并且 子类仍然访问 方法,但阻止其他人 改变收藏 直接。重复以下步骤: 另一边的收藏。

    更多参考文献