Skip navigation

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.

5 Comments

  1. Hi Shai,

    You just cannot imagine how thankful I am! I had such problem in my project and spent almost 2 days digging into blogs and forums, but did not see any useful solution.
    Today I had problems with configuring spring, and read your other post about it. Down down and saw @OnDelete(action = OnDeleteAction.CASCADE)

    Again thanks a lot!!!

  2. have you tried:

    @OneToMany(mappedBy = “parent”, cascade = CascadeType.ALL)
    @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    ;-)

  3. @Ninja – of course I have; the problem, as I said, is that wrong DDL is generated. That is, the foreign key IN THE UNDERLYING DB doesn’t have the on-delete-cascade property.

  4. for the love of god this has been driving me nuts. Thanks.

  5. Saved me a ton of time.. that authentication-provider/manager issue. Thanks!


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: