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 on Wednesday, January 25th, 2006 at 21:36 and is filed under Hibernate. You can follow any responses to this entry through the RSS 2.0 feed. Both comments and pings are currently closed.

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

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

    [...] now we only have the linktable reservations_tables. Exactly the same as we experienced with OneToMany relationships the cascading persist works when we persist a child (reservation). If we want the [...]