OneToMany relationships with Java Persistence (JSR 220)

Let’s experiment a bit with Hibernate. We want to model the tables employee and shift. Each employee has multiple shifts (and each shift belongs to an employee). We want an employee table and a shift table (which has the employee_id as a foreign key).

// Employee.java
@OneToMany(targetEntity=Shift.class) public List getShifts() {...}
// Shift.java
@ManyToOne public Employee getEmployee() {...}

The code above generates the following tables: employee, employee_shift and shift. Time to read the documentation and discover the mappedBy attribute.

// Employee.java
@OneToMany(targetEntity=Shift.class, mappedBy="employee") public List getShifts() {...}

Ok, now we get the tables we want. Let’s remove an employee that has shifts referencing him. An exception is thrown because of a foreign key constraint.

// Employee.java
@OneToMany(targetEntity=Shift.class, mappedBy="employee", cascade=CascadeType.REMOVE) public List getShifts() {...}

Ok, now we have cascading deletes working. Let’s try cascading inserts:

// Employee.java
@OneToMany(targetEntity=Shift.class, mappedBy="employee", cascade=CascadeType.ALL) public List getShifts() {...}
// Main.java
Employee employee = new Employee();
Shift shift = new Shift();
Vector shifts = new Vector();
shifts.add(shift);
employee.setShifts(shifts);
em.persist(employee);

With the code above the foreign key of shift will NULL instead of the employee_id. According to the documentation it is expected behaviour that cascading inserts only work when the children are saved.

// Employee.java
@OneToMany(targetEntity=Shift.class, mappedBy="employee", cascade=CascadeType.ALL) public List getShifts() {...}
// Main.java
Employee employee = new Employee();
Shift shift = new Shift();
shift.setEmployee(employee);
Vector shifts = new Vector();
shifts.add(shift);
employee.setShifts(shifts);
em.persist(employee);

It appears we can get cascading inserts to work as long as we don’t forget to set the employee. We add a constraint so employee can’t be null.

// Shift.java
@ManyToOne @Column(nullable=false) public Employee getEmployee() {...}
// Main.java
Shift shift = new Shift();
em.persist(shift);

WTF? I can persist a NULL reference anyway? The value for employee_id is allowed to be NULL? Have we found a bug? Let’s check the documentation:

// Shift.java
@ManyToOne @JoinColumn(nullable=false) public Employee getEmployee() {...}
// Main.java
Shift shift = new Shift();
em.persist(shift);

Ok, now are getting somewhere. And exception is thrown if we try to persist a shift that references to an employee that doesn’t exist in the database yet.

// Shift.java
@ManyToOne(cascade=CascadeType.PERSIST) @JoinColumn(nullable=false) public Employee getEmployee() {...}

CascadeType.ALL means that i want to cascade events on ALL events. My only requirements where that i cascade on PERSIST (insert) and on REMOVE (delete). So i need to change my annotation as following:

// Employee.java
@OneToMany(
  targetEntity=Shift.class,
  mappedBy="employee",
  cascade={
    CascadeType.PERSIST,
    CascadeType.REMOVE
  }
)
public List getShifts() {return shifts;}
This entry was posted in Uncategorized and tagged . Bookmark the permalink.

One Response to OneToMany relationships with Java Persistence (JSR 220)

  1. Pingback: Tim Van Wassenhove » Archive » ManyToMany relationships with Java Persistence (JSR-220)

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>