Currently we have an issue (a well known one) with Spring Data JPA
+ Spring Data REST
(Hibernate
as JPA
implementation) when trying to update the collection (relation) which is a not the owning side.
The mapping is the following:
@Entity(name = Product.NAME)
public class Product {
...
@OneToMany(mappedBy = "baseProduct", fetch = FetchType.LAZY, targetEntity = Variant.class)
List<Variant> getVariants() {
...
and on the other variant side:
@Entity(name = Variant.NAME)
public class Variant extends Product {
...
@ManyToOne(fetch = FetchType.LAZY, targetEntity = Product.class)
@JoinColumn(name = "baseproduct_id", referencedColumnName = "id")
Product getBaseProduct() {
...
}
all is good on the Java side if you use Spring Data JPA
only, however if you want to update the "product" by updating its collection of variants and send PATCH
request to https://localhost:8112/storefront/rest/product/21394435410197232 containing the payload of the new collection only (having 2 out of the 3 items):
{"variants":["22801810293768080","22801810293768096"]}
I get no exceptions or anything but since the owning side is the other side nothing is persisted and I got the old 3 items
again.
I know
that I can fix this by setting
@JoinColumn(name = "baseproduct_id", referencedColumnName = "id")
on both sides and not use mappedBy
anywhere, however I have heard there is a performance implication which I am not sure how big it is (we got 100+ entities having @OneToMany
) and I wonder is there better workaround via @PreUpdate
listener or something ?
You have to synchronize both sides of the bidirectional association, and also add on orphanRemoval
and Cascade
.
So, your mapping becomes:
@OneToMany(
mappedBy = "baseProduct",
fetch = FetchType.LAZY,
targetEntity = Variant.class
cascade = CascadeType.ALL,
orphanRemoval = true)
List<Variant> getVariants() {
And the two add/remove methods:
public void addVariant(Variant variant) {
getVariants().add(variant);
variant.setBaseProuct(this);
}
public void removeVariant(Variant variant) {
variant.setBaseProuct(null);
this.getVariants().remove(variant);
}
You need to implement equals
and hashCode
methods in the Variant
child entity for the add
and remove
methods to work effectively.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With