Hibernate 级联删除 ConstraintViolationException
Hibernate cascade remove ConstraintViolationException
看起来情况很简单(但是不行)。
Db 部分(EVENT_ID
是外键。FK_RR_E_CI
EVENT
table 上的约束引用)
|-------| |----------------|
| 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;
}
如果我尝试删除事件对象,它将 return:
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
SAVE
和 UPDATE
操作正常。
我应该在我的映射中更改什么才能使用级联删除?
我知道我应该使用 @OnDelete(action=OnDeleteAction.CASCADE)
但我不明白如何使用它...
不要在 @OneToMany
注释中使用 cascade = CascadeType.ALL
属性,而是像这样使用 Hibernate 的 @Cascade()
注释:
@OneToMany(orphanRemoval = true, mappedBy = "event")
@Cascade({CascadeType.ALL})
private Set<RecurrentRule> recurrentRules = new HashSet<>();
因为 cascade = CascadeType.ALL
是一个 JPA 选项,所以当 Hibernate session 试图删除对象时,它会搜索一个 Hibernate Cascade,它不会找到它,这就是为什么你应该使用 @Cascade
.
如需进一步阅读,请查看 Cascade – JPA & Hibernate annotation common mistake,它给出了更好的解释。
似乎关系很深有问题。在 event
以上的层次结构中,我在日历之前有 calendar
,我有 profile
。为了解决这种关系,我使用了 @OnDelete(action = OnDeleteAction.CASCADE)
但这对我来说还不够。对于描述的案例 Event
<=> RecurrentRule
关系,我已经为 Event 实现了监听器并且我使用了一个 @EntityListeners({EntityEventJpaCallbacksListener.class})
参见 import [javax.persistence.EntityListeners][1];
@Component
public class EntityEventJpaCallbacksListener {
@PreRemove
void preRemove(Event event) {
ContextAware.getBean(RecurrentRuleRepository.class).deleteByEvent(event);
}
}
看起来情况很简单(但是不行)。
Db 部分(EVENT_ID
是外键。FK_RR_E_CI
EVENT
table 上的约束引用)
|-------| |----------------|
| 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;
}
如果我尝试删除事件对象,它将 return:
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
SAVE
和 UPDATE
操作正常。
我应该在我的映射中更改什么才能使用级联删除?
我知道我应该使用 @OnDelete(action=OnDeleteAction.CASCADE)
但我不明白如何使用它...
不要在 @OneToMany
注释中使用 cascade = CascadeType.ALL
属性,而是像这样使用 Hibernate 的 @Cascade()
注释:
@OneToMany(orphanRemoval = true, mappedBy = "event")
@Cascade({CascadeType.ALL})
private Set<RecurrentRule> recurrentRules = new HashSet<>();
因为 cascade = CascadeType.ALL
是一个 JPA 选项,所以当 Hibernate session 试图删除对象时,它会搜索一个 Hibernate Cascade,它不会找到它,这就是为什么你应该使用 @Cascade
.
如需进一步阅读,请查看 Cascade – JPA & Hibernate annotation common mistake,它给出了更好的解释。
似乎关系很深有问题。在 event
以上的层次结构中,我在日历之前有 calendar
,我有 profile
。为了解决这种关系,我使用了 @OnDelete(action = OnDeleteAction.CASCADE)
但这对我来说还不够。对于描述的案例 Event
<=> RecurrentRule
关系,我已经为 Event 实现了监听器并且我使用了一个 @EntityListeners({EntityEventJpaCallbacksListener.class})
参见 import [javax.persistence.EntityListeners][1];
@Component
public class EntityEventJpaCallbacksListener {
@PreRemove
void preRemove(Event event) {
ContextAware.getBean(RecurrentRuleRepository.class).deleteByEvent(event);
}
}