2017-01-20 28 views
8

Obecnie mamy problem (znanej jeden) z Spring Data JPA + Spring Data REST (Hibernate jako JPA realizacji) podczas próby aktualizacji zbiórki (relacja), który jest nie po stronie właściciela.Wiosna danych REST + JPA usunąć z kolekcji OneToMany [nie właściciel bocznej]

Odwzorowanie jest następujące:

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

i po drugiej stronie Wariant:

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

wszystko jest dobry na stronie Java jeśli używasz Spring Data JPA tylko jednak jeśli chcesz zaktualizować "produkt", aktualizując jego kolekcję wariantów i wysyłając żądanie PATCH do https://localhost:8112/storefront/rest/product/21394435410197232 zawierające ładunek nowa kolekcja tylko (o 2 z 3 pozycji):

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

otrzymuję żadnych wyjątków ani nic, ale skoro strona będącym właścicielem jest druga strona nie jest utrwalane i mam starą 3 items ponownie.

I know że mogę rozwiązać ten problem przez ustawienie

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

na obustronnie i nie używać mappedBy wszędzie, jednak słyszałem, że jest implikacja wydajność których nie jestem pewien, jak duży jest to (mamy 100+ encji mających @OneToMany) i zastanawiam się, czy istnieje lepsze obejście przez słuchacza @PreUpdate czy coś takiego?

Odpowiedz

5

Jak wyjaśniono w this article, należy zsynchronizować obie strony skojarzenia dwukierunkowego, a także dodać opcję orphanRemoval i Cascade.

Więc Twój mapowanie staje:

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

i dwie Dodaj/Usuń metod:

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

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

Dla metody Usuń, aby działał poprawnie, trzeba zaimplementować equals i hashCode as explain in this article.

+0

Dzięki, jednak obecnie nie chcę usuwać sierot, chcę tylko usunąć "połączenie", nie usuwając żadnej strony :) Również nie jestem wielkim fanem kaskady i być może brakuje mi coś, ale metody addXXX i removeXXX będą w jakiś sposób wywoływane przez Spring Data Rest? – JOKe

+1

Następnie masz złe mapowanie, ponieważ nie podano '@ JoinTable'. Jeśli masz tabelę sprzężenia, najlepszym sposobem na odwzorowanie jest mapowanie tabeli łączenia jako jednostki pośredniej, która ma 2 asocjacje '@ManyToOne'. Mam przykład w mojej książce [High-Performance Java Persistence] (https://leanpub.com/high-performance-java-persistence). –