Hibernate级联删除ConstraintViolationException

时间:2017-07-05 21:43:01

标签: java hibernate hibernate-mapping foreign-key-relationship cascade

情况似乎很简单(但不起作用)。 Db部分(EVENT_ID是外键。FK_RR_E_CI表上的EVENT约束引用

 |-------|            |----------------|
 | EVENT | 1 ------ ∞ | RECURRENT_RULE |
 |-------|            |----------------|
 | ID    |            | ID             |
 |-------|            | EVENT_ID       |
                      |----------------|

Java部分:

@Entity
public class Event {
  @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "event")
  private Set<RecurrentRule> recurrentRules = new HashSet<>();
}

@Entity
public class RecurrentRule {
  @ManyToOne
  @JoinColumn(columnDefinition = "event_id")
  private Event event;
}

如果我尝试删除事件对象它将返回:

could not execute statement; SQL [n/a]; constraint [MY_SCHEMA.FK_RR_E_CI]; 
nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
...
java.sql.SQLIntegrityConstraintViolationException: ORA-02292: integrity constraint (MY_SCHEMA.FK_RR_E_CI) violated - child record found

SAVEUPDATE操作正常运行。

我的映射中应该更改什么才能使用级联删除? 我知道我应该使用@OnDelete(action=OnDeleteAction.CASCADE),但我无法理解如何使用它......

2 个答案:

答案 0 :(得分:2)

不要在cascade = CascadeType.ALL注释中使用@OneToMany属性,而是使用Hibernate的@Cascade()注释,如下所示:

@OneToMany(orphanRemoval = true, mappedBy = "event")
@Cascade({CascadeType.ALL})
private Set<RecurrentRule> recurrentRules = new HashSet<>();

因为cascade = CascadeType.ALL是一个JPA选项,所以当Hibernate会话试图删除该对象时,它会搜索一个Hibernate Cascade,它找不到它,这就是你应该使用@Cascade的原因。

如需进一步阅读,请查看Cascade – JPA & Hibernate annotation common mistake,它会给出更好的解释。

答案 1 :(得分:1)

关系的深层似乎存在问题。在event上方的层次结构中,我在日历之前calendar profile。为了解决这种关系,我使用了@OnDelete(action = OnDeleteAction.CASCADE)但这对我的情况来说还不够。对于描述的案例Event&lt; =&gt; RecurrentRule关系我为事件实施了监听器,我使用了@EntityListeners({EntityEventJpaCallbacksListener.class}) import [javax.persistence.EntityListeners][1];

@Component
public class EntityEventJpaCallbacksListener {
    @PreRemove
    void preRemove(Event event) {
        ContextAware.getBean(RecurrentRuleRepository.class).deleteByEvent(event);
    }
}