Skip navigation

Tag Archives: Hibernate

Even though I’ve been working with Hibernate for 3 years now, I’ve only just run into this issue – most likely because in past projects we’ve used POJO generations and now, for the first time in a real life project, I’m using the Schema Export tool.

It turns out that, for some odd reason, when creating foreign keys for OneToMany / ManyToOne relationships, Hibernate completely ignore the @Cascade annotations or the cascade keyword of the join annotation.

For instance, consider the following model:


@Entity
public class Cat {

 @Id
 @GeneratedValue
 @Column
 private Long id;

 @Column
 private String name;

 @OneToMany(mappedBy = "parent", cascade = {CascadeType.ALL})
 @ForeignKey(name = "FK_KITTEN_PARENT")
 private List kittens = new ArrayList();

}

@Entity
public class Kitten {

 @Id
 @Column
 @GeneratedValue
 private Long id;

 @ManyToOne(cascade = CascadeType.ALL)
 private Cat parent;

 @Column
 private String name;
}

The resulting DDL for these two classes will be:

create table Cat (id bigint not null auto_increment, name varchar(255), primary key (id)) ENGINE=InnoDB

create table Kitten (id bigint not null auto_increment, name varchar(255), parent_id bigint, primary key (id)) ENGINE=InnoDB

alter table Kitten add index FK_KITTEN_PARENT (parent_id), add constraint FK_KITTEN_PARENT foreign key (parent_id) references Cat (id)

This behavior does not seem to be documented anywhere. The Hibernate guys seem to think it’s natural for people to assume that the CascadeType and @Cascade definitions are not translated into DDL. What Hibernate does, instead of generating DDL, is automatically deleting the children (Kittens, in our case) of a deleted parent, when you use the Criteria API. And what if you happen to use HQL? tough.

Fortunately, there IS a solution. It involves using the not-so-well documented annotation (or XML attribute) @OnDelete on the parent (Cat, in our case) side of the association, thus:

@Entity
public class Cat {

@Id
@GeneratedValue
@Column
private Long id;

@Column
private String name;

@OneToMany(mappedBy = "parent", cascade = {CascadeType.ALL})
@ForeignKey(name = "FK_KITTEN_PARENT")
@OnDelete(action = OnDeleteAction.CASCADE)
private List<Kitten> kittens = new ArrayList<Kitten>();

This ensures that the foreign key is created with the appropriate on delete cascade clause and allowing you to safely delete your parent entities not worrying about any children that refer to them.