Search code examples
javamysqldatabasejpaeclipselink

JPA Cascade a abstract/inherit Class on Delete


I have an abstract class TreeNode. From him i inherit the classes Country and Location. Then I have a class Role that includes predefined roles like administrator, user etc. These two classes are mapped together in the MappedRole class. The database table of mappedRole has columns treenode_id role_id und mappedRole_id. The tables in the database look alike I have a table for country and location because I create Treenode with Table_per_Class. Therefore the table MappedRole has no ForeignKey for country and location.The treenode_id column in mappedRole contains then the id of the class its mapped to. JPA gets the relation with a big join on both tables.

This is my MappedRole Class:

@Table(uniqueConstraints = { @UniqueConstraint(columnNames = { "TREENODE_ID", "ROLE_ID" }) }, name = "mappedrole")
@NamedQueries({ @NamedQuery(name = "mappedRole.checkIfUserExist", query = "SELECT count(mr.role) FROM MappedRole mr WHERE mr.role =?1") })
public class MappedRole implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @ManyToOne(cascade = { CascadeType.REMOVE }, fetch = FetchType.EAGER)
    @JoinColumn(name = "TREENODE_ID", nullable = false)
    private TreeNode treeNode;

    @ManyToOne(cascade = { CascadeType.MERGE, CascadeType.REMOVE, CascadeType.REFRESH }, fetch = FetchType.EAGER)
    @JoinColumn(name = "ROLE_ID")
    private Role role;

TreeNode class:

@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class TreeNode extends Observable {
        @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    protected long id;

and the location class:

@Entity
@Table(name = "standort")
@NamedQuery(name = "standort.findAll", query = "SELECT s FROM Standort s order by s.name desc")
public class Standort extends TreeNode implements Comparable<Standort>, Serializable {

If I now delete a location the mappedRole will not be deleted even though I have CascadeType.REMOVE. How can i make jpa cascade the delete operation of a location to the mappedRole table?


Solution

  • Cascading only works for the entity it is declared in. I.e.,

    public class MappedRole {
    
      @ManyToOne(cascade = { CascadeType.REMOVE }, fetch = FetchType.EAGER)
      @JoinColumn(name = "TREENODE_ID", nullable = false)
      private TreeNode treeNode;
    

    Should delete all corresponding TreeNodes if and when a MappedRole is deleted.

    You don't seem to have the inverse @OneToMany relationship in TreeNode or Standort, so when you delete a TreeNode or Standort there's no relation on which JPA could cascade anything.

    Try it like this:

    @MappedSuperclass
    @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
    public abstract class TreeNode ... {
    
      @OneToMany(cascade= { CascadeType.REMOVE }, mappedBy="treeNode" )
      private List<MappedRole> mappedRoles;
    

    and make sure to put each MappedRole also into the mappedRoles list of it's owning TreeNode.