Consider the following entity model:
The dossier entity.
@Entity
@Table(name = "dossiers", uniqueConstraints = @UniqueConstraint(columnNames = { "site_id", "dossier_id" }))
@Audited(withModifiedFlag = true)
@Access(AccessType.FIELD)
public final class Dossier extends EntityObject {
@Column(name = "name", nullable = false, length = 255)
private String name;
@OneToOne(fetch = FetchType.EAGER, mappedBy = "dossier", optional = true, cascade = CascadeType.ALL, orphanRemoval = true)
private Commission commission;
}
The commissions entity.
@Entity
@Table(name = "commissions")
@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
@Access(AccessType.FIELD)
public class Commission extends EntityObject{
@Column(name = "name")
private String name;
@OneToMany(mappedBy = "commission", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
@OrderBy(clause = "boundary ASC NULLS LAST")
private List<CommissionBracket> commissionBrackets;
@OneToOne(optional = true)
@JoinColumn(name = "dossier_id", nullable = true)
private Dossier dossier;
}
The bracket entity.
@Entity
@Table(name = "commission_brackets")
@Access(AccessType.FIELD)
public class CommissionBracket extends EntityObject {
@ManyToOne(optional = false)
@JoinColumn(name = "commission_id")
private Commission commission;
@Column(name = "boundary")
private Integer boundary;
}
Now when I want to replace the commission from a dossier. I have to do this:
boolean notSaved = true;
if(domain.getCommission() != null) {
toSave.setCommission(domain.getCommission());
toSave.getCommission().getCommissionBrackets().clear();
toSave = dossierRepository.save(toSave);
toSave.setCommission(null);
toSave = dossierRepository.save(toSave);
notSaved = false;
}
if(dossier.getCommission() != null) {
final Commission newCommission = commissionRepository.save(dossier.getCommission());
toSave.setCommission(newCommission);
toSave = dossierRepository.save(toSave);
notSaved = false;
}
if(notSaved) {
toSave = dossierRepository.save(toSave);
}
Note that the save operation on a repository does a persist or merge depending on whether the object passed has its id set or not.
While a normal person with a sane mind would think that he could simply do:
dossier.setCommission(newCommission);
dossierRepository.save(newCommission);
For some reason, regardless if there are brackets attached to the commission or not I need to:
- Clear the brackets on the existing commission
- Save
- Remove the existing commission
- Save
- Persist the new commission
- Set the new commission on the Dossier
- Save
Skipping any of the steps causes this error:
A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: Commission.commissionBrackets
While there might be a plausible explanation for this it feels very ugly and maybe there is a cleaner way to do it? Instead of removing the existing commission I could also update it entirely but that would not reflect the functional reality.
Hibernate version used is: 4.3.10.Final DB used: postgres 9.4.4.1
So my questions are. Am I doing it right or it be improved somewhere?
You didn't post all relevant entity details, like
Commission
's relation toDossier
, butmappedBy
says it is there. SinceDossier
is in a bidirectional relation toCommission
(andCommission
happens to be the owning side of the relation), you just need to maintain both sides. This should work: