2017-01-20 2 views
8

Derzeit haben wir ein Problem (ein gut einem bekannten) mit Spring Data JPA + Spring Data REST (Hibernate als JPA Implementierung) beim Versuch, die Sammlung (Beziehung) zu aktualisieren, die ein nicht die besitzende Seite.Spring Data REST + JPA entfernen OneToMany Sammlung [nicht Eigentümer Seite]

Die Abbildung ist die folgende:

@Entity(name = Product.NAME) 
public class Product { 
... 
@OneToMany(mappedBy = "baseProduct", fetch = FetchType.LAZY, targetEntity = Variant.class) 
List<Variant> getVariants() { 
... 

und auf der anderen Variante Seite:

@Entity(name = Variant.NAME) 
public class Variant extends Product { 
... 
@ManyToOne(fetch = FetchType.LAZY, targetEntity = Product.class) 
@JoinColumn(name = "baseproduct_id", referencedColumnName = "id") 
Product getBaseProduct() { 
... 
} 

alles ist gut auf der Java Seite, wenn Sie Spring Data JPA nur verwenden, aber wenn Sie möchten das "Produkt" aktualisieren, indem Sie seine Variantensammlung aktualisieren und PATCH Anfrage an https://localhost:8112/storefront/rest/product/21394435410197232 senden, die die Nutzlast von enthält nur die neue Kollektion (mit von 2 der 3 Artikel):

{"variants":["22801810293768080","22801810293768096"]} 

ich keine Ausnahmen oder etwas bekommen, aber da der besitzende Seite die andere Seite nichts beibehalten wird, und ich bekam die alte 3 items wieder.

ich know, die ich dieses Problem beheben, indem

@JoinColumn(name = "baseproduct_id", referencedColumnName = "id") 

auf Einstellung beide Seiten und mappedBy nicht überall benutzen, aber ich habe gehört, dass es eine Leistung Implikation ist, was ich bin nicht sicher, wie groß es ist (Wir haben 100+ Entitäten mit @OneToMany) und ich frage mich, gibt es bessere Workaround über @PreUpdate Listener oder etwas?

Antwort

5

Wie unter this article erläutert, müssen Sie beide Seiten der bidirektionalen Verknüpfung synchronisieren und auch orphanRemoval und Cascade hinzufügen.

So, Ihr Mapping wird:

@OneToMany(
    mappedBy = "baseProduct", 
    fetch = FetchType.LAZY, 
    targetEntity = Variant.class 
    cascade = CascadeType.ALL, 
    orphanRemoval = true) 
List<Variant> getVariants() { 

Und die beiden Add/Remove-Methoden:

public void addVariant(Variant variant) { 
    getVariants().add(variant); 
    variant.setBaseProuct(this); 
} 

public void removeVariant(Variant variant) { 
    variant.setBaseProuct(null); 
    this.getVariants().remove(variant); 
} 

Für das Entfernen Methode richtig funktioniert, müssen Sie as explain in this article equals und hashCode implementieren.

+0

Danke, aber momentan möchte ich nicht die Waisenkinder entfernen Ich möchte nur die "Verbindung" entfernen, keine der Seite zu entfernen :) Auch ich bin kein großer Fan von Kaskade (n) und vielleicht bin ich vermisst etwas, aber die addXXX und removeXXX-Methoden werden von Spring Data Rest irgendwie aufgerufen? – JOKe

+1

Dann haben Sie die falsche Zuordnung, weil Sie kein '@ JoinTable' angegeben haben. Wenn Sie eine Join-Tabelle haben, ist es am besten, die Join-Tabelle als intermediäre Entität mit 2 '@ManyToOne'-Zuordnungen zuzuordnen. Ich habe ein Beispiel in meinem Buch, [High-Performance Java Persistence] (https://leanpub.com/high-performance-java-persistence). –

Verwandte Themen