Reputation: 1086
I know that there is already a ton of questions referring to this error, but non of the solutions seems to apply.
I want to create or update
parent entities "p" and always delete old and create new
children entities "c".
On a Service, under an Async Controller with:
@Async("SomeExecutor")
@Transactional(propagation = Propagation.REQUIRES_NEW)
I am doing the following:
private SessionFactory sessionFactory;
Session session = this.sessionFactory.getCurrentSession();
for (int i = 0; i < dtoListOfParents.size(); i++) {
ParentEntity p = null;
if(peKeyMap.contains(paKey)){ //just a map with the already existing ParentEntities that I fetch beforehand.
p = peKeyMap.get(paKey);
} else {
p = new ParentEntity();
}
p.setSomeProperty(v1);
p.setSomeOtherProperty(v2);
if(p.getId()==null){
p = (ParentEntity) session.merge(p);
} else {
p.getC.clear();
}
session.flush(); //to get parent id for on create or delete the children on edit.
p.setC(dtoListOfCs, p);
if (i % 50 == 0) {
session.flush(); // Here is where I am getting the error.
session.clear();
}
}
Hibernate is "complaining" about the following:
org.hibernate.HibernateException: A collection with cascade="all-delete-orphan"
was no longer referenced by the owning entity instance: ...model.ParentEntity.children
The Children entity:
@Entity
@Table(name = "children")
@DynamicInsert
@DynamicUpdate
public class Children implements Serializable {
private static final long serialVersionUID = 1L;
private ChildrenPK pk;
private ParentEntity parentEntity;
private SecondaryEntity secondaryEntity;
@EmbeddedId
public ChildrenPK getPk() {
return pk;
}
public void setPk(ChildrenPK pk) {
this.pk = pk;
}
public Children() {
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="parent_entity_id", nullable=false, insertable=true, updatable=false)
@MapsId("parentEntityId")
public ParentEntity getParentEntity() {
return this.parentEntity;
}
The association on the ParentEntity side:
@OneToMany(mappedBy = "parentEntity", cascade = { CascadeType.ALL }, orphanRemoval = true, fetch = FetchType.LAZY)
public List<Children> getChildren() {
return children;
}
Upvotes: 1
Views: 8773
Reputation: 10726
You code is a little... peculiar, but is this line:
p.setC(dtoListOfCs, p);
overwriting Parent.children
with a fresh collection?
Hibernate doesn't like it when you override a collection property of a managed entity with a fresh collection when the mapping is annotated with @OneToMany(orphanRemoval = true)
. You need to use the original list instead, adding/removing children, and clearing it, if necessary.
(Note that the Parent
entity returned from session.merge()
will already have an empty collection created by Hibernate, even if it was null
before the merge. You're supposed to use that one)
Upvotes: 4