简体   繁体   中英

Hibernate cascade remove ConstraintViolationException

It seems the situation is simply (but it does not work). Db part ( EVENT_ID is foreign key. FK_RR_E_CI constraint references on EVENT table)

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

Java part:

@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;
}

If I try to delete event object It will 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 and UPDATE operations work correctly.


What should I change in my mapping to be able use cascade removal? I know that I should use @OnDelete(action=OnDeleteAction.CASCADE) but I can't understand how to use it...

Instead of using cascade = CascadeType.ALL attribute in the @OneToMany annotation, use Hibernate's @Cascade() annotation like this:

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

Because cascade = CascadeType.ALL is a JPA option, so when Hibernate session tries to delete the object, it will search for a Hibernate Cascade, it won't find it, that's why you should use @Cascade .

For further reading take a look at Cascade – JPA & Hibernate annotation common mistake , it gives a better explanation.

It seems has an issue with deep of relations. In hierarchy above event I have calendar before calendar I have profile . To resolve this relations I've used @OnDelete(action = OnDeleteAction.CASCADE) but it was not enough for my case. For described case Event <=> RecurrentRule relation I've implemented listener for Event and I've used one @EntityListeners({EntityEventJpaCallbacksListener.class}) see import [javax.persistence.EntityListeners][1];

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM