JPA Cascading Delete: Setting child FK to NULL on NOT NULL column
I have two tables, t_promo_program and t_promo_program_param.
They are represented by the following JPA entities:
@Entity
@Table(name = "t_promo_program")
public class PromoProgram {
@Id
@Column(name = "promo_program_id")
private Long id;
@OneToMany(cascade = {CascadeType.REMOVE})
@JoinColumn(name = "promo_program_id")
private List<PromoProgramParam> params;
}
@Entity
@Table(name = "t_promo_program_param")
public class PromoProgramParam {
@Id
@Column(name = "promo_program_param_id")
private Long id;
//@NotNull // This is a Hibernate annotation so that my test db gets created with the NOT NULL attribute, I'm not married to this annotation.
@ManyToOne
@JoinColumn(name = "PROMO_PROGRAM_ID", referencedColumnName = "promo_program_id")
private PromoProgram promoProgram;
}
When I remove PromoProgram Hibernate removes my database with
update
T_PROMO_PROGRAM_PARAM
set
promo_program_id=null
where
promo_program_id=?
delete
from
t_promo_program
where
promo_program_id=?
and last_change=?
I don't know where to start looking for the source of the problem.
a source to share
Double check if you maintain consistency in bidirectional communication. I.e; make sure all PromoProgramParam
objects that are referenced PromoProgram
as a parent are also in the specified parent list params
. It's a good idea to make sure this happens no matter which side "initiates" the association, if you do; if setPromoProgram is called on PromoProgramParam, let the setter automatically add itself to the PromoProgram list params
. Conversely, when you call addPromoProgramParam on PromoProgram, set it as the parent parameter.
I have encountered this problem before and it was due to lack of support for bidirectional consistency. I was debugging in Hibernate and found that it was unable to cascade the delete operation for the children, because they were not in the list. However, they were certainly present in the database and threw FK exceptions, since Hibernate tried to delete only the parent without first deleting its children (which you probably also met with @NonNull in place).
FYI, I believe the correct "EJB 3.0" way to make the PromoProgramParam.promoProgram field (say 100 times) non-null is to set the optional = false attribute in the @ManyToOne annotation.
a source to share