Hibernate annotates many-to-one without adding children to the parent collection

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 one-to-many / many-one bi-directional relationship between "Cat" and "Kitten", and the kitten is the "owning side".

What I want to do is when I create a new Cat and then a new kitten referring to Cat. The kitten kit on my cat should contain a new kitten . However, this fails 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 retrying Cat, 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 the burden for me to manage the collection myself? The documentation (annotations) does not indicate that I need to create convenient addTo* / removeFrom* methods for my parent object.

Can someone please enlighten me, what are my expectations from Hibernate with this relationship? Or, if nothing else, give me the correct Hibernate documentation that will tell me what I should expect here.

What do I need to do so that the parent collection automatically contains a child Entity?

+6
java hibernate jpa hibernate-annotations many-to-one
source share
2 answers

It will not automatically add it. You must add it yourself.

I would not call Kitten.setCat() directly. A typical template for this is to put the method in Cat as:

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

and then just call:

 cat.addKitten(kitten); 
+14
source share

When working with bidirectional associations, you must process both sides of the “link”, and very often use security link management methods for this, as suggested by @cletus. From the Hibernate Core documentation:

1.2.6. Work Bidirectional Links

First, keep in mind that Hibernate does not affect the usual semantics of Java. How did we create the connection between Man and event in a unidirectional example? You add an instance of an event to the collection of an event reference, an instance of Man. If you want to make this link bi-directional, you must do the other hand by adding the Link person to the collection to the event. This process of “establishing a link on both sides” is absolutely necessary with bidirectional links.

Many developers protect themselves and create link management methods to correctly set both sides (for example, in the Face):

 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 one package and subclasses to access methods, but prevents everyone else from changing collections directly. Repeat the steps for the other side.

Sitelinks

+3
source share

All Articles