StormyWaters StormyWaters - 3 months ago 19
Java Question

OpenJPA - Nested OneToMany relationships merge issue

Posting this here as I wasn't seeing much interest here: http://www.java-forums.org/jpa/96175-openjpa-one-many-within-one-many-merge-problems.html

Trying to figure out if this is a problem with OpenJPA or something I may be doing wrong...

I'm facing a problem when trying to use OpenJPA to update an Entity that contains a One to Many relationship to another Entity, that has a One to Many relationship to another. Here's a quick example of what I'm talking about:

@Entity
@Table(name = "school")
public class School {

@Column(name = "id")
protected Long id;

@Column(name = "name")
protected String name;

@OneToMany(mappedBy = "school", orphanRemoval = true, cascade = CascadeType.ALL)
protected Collection<ClassRoom> classRooms;
}

@Entity
@Table(name = "classroom")
public class ClassRoom {

@Column(name = "id")
protected Long id;

@Column(name = "room_number")
protected String roomNumber;

@ManyToOne
@JoinColumn(name = "school_id")
protected School school;

@OneToMany(mappedBy = "classRoom", orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
protected Collection<Desk> desks;

}

@Entity
@Table(name = "desk")
public class Desk {

@Column(name = "id")
protected Long id;

@ManyToOne
@JoinColumn(name = "classroom_id")
protected ClassRoom classRoom;

}


In the SchoolService class, I have the following update method:

@Transactional
public void update(School school) {
em.merge(school);
}


I'm trying to remove a Class Room from the School. I remove it from the classRooms collection and call update. I'm noticing if the Class Room has no desks, there are no issues. But if the Class Room has desks, it throws a constraint error as it seems to try to delete the Class Room first, then the Desks. (There is a foreign key constraint for the classroom_id column)

Am I going about this the wrong way? Is there some setting I'm missing to get it to delete the interior "Desk" instances first before deleting the Class Room instance that was removed?

Any help would be appreciated. If you need any more info, please just let me know.
Thanks,

Answer

There are various bug reports around FK violations in OpenJPA when cascading remove operations to child entities:

The OpenJPA FAQ notes that the following:

http://openjpa.apache.org/faq.html#reorder

Can OpenJPA reorder SQL statements to satisfy database foreign key constraints?

Yes. OpenJPA can reorder and/or batch the SQL statements using different configurable strategies. The default strategy is capable of reordering the SQL statements to satisfy foreign key constraints. However ,you must tell OpenJPA to read the existing foreign key information from the database schema:

It would seem you can force the correct ordering of the statements by either setting the following property in your OpenJPA config

<property name="openjpa.jdbc.SchemaFactory"> value="native(ForeignKeys=true)"/>

or by adding the org.apache.openjpa.persistence.jdbc.ForeignKey annotation to the mapping:

@OneToMany(mappedBy = "classRoom", orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@org.apache.openjpa.persistence.jdbc.ForeignKey
protected Collection<Desk> desks;

See also:

https://issues.apache.org/jira/browse/OPENJPA-1936