Issue
There is some code in a Spring Boot project (simplified for brevity) :
@Transactional
public void serviceMethod() {
var child = Child.builder().value(...).build();
var parent = parentEntityRepository.findById(5);
child.setParent(parent);
parent.getChildren().clear();
parent.getChildren().add(child);
}
@Entity
public class Parent {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL,orphanRemoval = true)
@Fetch(FetchMode.SUBSELECT)
private List<Child> children = new ArrayList<>();
}
@Entity
public class Child {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "parent_id")
private Parent parent;
// this field has UNIQUE constaint in the project's Postgres DB
private String value;
}
and child_table has UNIQUE index on the one of its columns. I can't understand, why it doesn't work, failing with "unique contstraint violation error". As I read here, Hibernate flushing order starts with OrphanRemovalAction, so the code above seems to be correct, but while checking Hibernate logs with generated native SQL there were not any DELETE statements issued after transaction had been commited.
Solution
There is a known Hibernate bug describing this problem.
Currently, the cascade executes the INSERT
of the new entity before the DELETE
(ophan-removal).
To work around it, you may just flush the session once after clearing the list. This way the orphan-removal is done before also cascading a persist to a newly associated child (which triggers its insertion).
Answered By - fladdimir
Answer Checked By - Katrina (JavaFixing Volunteer)