Issue
I need to store normalized (i.e. without special characters etc.) variants of some of the String
fields of some entities.
An example:
@Entity
public class Car {
@Id
private Long id;
private String make;
private String model;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "CAR_ID")
private Set<NormalizedField> normalizedFields = new HashSet();
private Set<NormalizedField> createNormalizedFields(Car car) {
Set<NormalizedField> normalized = normalize(car);
this.normalizedFields.clear();
this.normalizedFields.addAll(normalized);
}
// I would use this approach, but it doesn't allow
// changes to related entities.
// @PreCreate
// public void onCreate() {
// createNormalizedFields();
// }
}
@Entity
public class NormalizedField {
@Id
private Long id;
private String fieldName;
private String normalizedValue;
}
It would be convenient if the normalized values were automatically (re)created whenever the Car
entity is persisted. Is there a way to trigger the creation method automatically?
Using @PrePersist, @PreUpdate
... is obviously not an option as it doesn't allow changes to related entities.
Spring AOP is not used in the project, so I would rather avoid introducing it for now. But it's an option anyways.
The application is huge, and managing the normalized values 'manually' would require quite a bit of work, hence I leave it as the last option.
Solution
Going to post this half-answer here ('half' because it provides a workaround with restrictions).
In some cases org.hibernate.Interceptor
can be used to manage child entities whenever the parent entity is changed.
But there are restrictions: the javadoc says Session
is not to be used in the Interceptor
. JPA repository methods, JPQL or HQL calls are intercepted by the same Interceptor
in a loop. Even native queries get intercepted unless you set FlushMode.COMMIT
or FlushMode.MANUAL
(and maybe some other).
The above means you'll probably have to use the datasource directly. I don't remember exactly how, but Spring provides means to execute queries using datasource directly and within current transaction. In my case it was enough as I had to manage some technical child entities that didn't need a representation as an Entity
.
Answered By - Arctic_fox
Answer Checked By - Pedro (JavaFixing Volunteer)