views:

119

answers:

2

Table SUBCOURSE references COURSE COURSE(id, name) SUBCOURSE(id, course_id, name)

So, 1:M.

Hibernate generates for Course:

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "course", cascade = CascadeType.ALL)
    public Set getSubCourses() {
        return this.subCourses;
    }

for Subcourse it generates

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "course_id", nullable = false)
    public Course getCourse() {
        return this.course;
    }

Now the problem is that cascading does not work as expected. I want to create a collection of SubCourse objects (Set), fill it and then bind it to setSubCourses() of Course object. Then simply persist the Course object.

Though, having ManyToOne thing in a Subcourses table, I need to manually setCourse() before adding to collection on each object. If I do not do so, an exception is raised when persisting Course object with its collection.

What can you recommend me?

P.S. or maybe this is part of the game? setting a parent object of every child by hand?

+2  A: 

It seems that this is part of the game. Quote from the Hibernate book (referring to an example where Item is the parent and Bid is the child):

If you only call anItem.getBids().add(bid), no changes are made persistent! You get what you want only if the other side, aBid.setItem(anItem), is set correctly. This is consistent with the behavior in Java without Hibernate: If an association is bidirectional, you have to create the link with pointers on two sides, not just one. It’s the primary reason why we recommend convenience methods such as addBid() — they take care of the bidirectional references in a system without container- managed relationships.

The class referred to above is

public class Item {
  ...
  private Set bids = new HashSet();
  public void setBids(Set bids) {
    this.bids = bids;
  }
  public Set getBids() {
    return bids;
  }
  public void addBid(Bid bid) {
    bid.setItem(this);
    bids.add(bid);
  }
  ...
}
Péter Török
A: 

When working with a bi-directional association, it is necessary to set both sides of the link correctly (as documented in 1.2.6. Working bi-directional links). I often use the defensive approach suggested in the documentation:

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.

Pascal Thivent