JPA CascadeType.ALL nie usuwa sierot

132

Mam problem z usunięciem węzłów osieroconych przy użyciu JPA z następującym mapowaniem

@OneToMany (cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "owner")
private List<Bikes> bikes;

Mam problem z osieroconymi rolami kręcącymi się po bazie danych.

Mogę użyć adnotacji org.hibernate.annotations.Cascade specyficznej dla Hibernate tag, ale oczywiście nie chcę wiązać mojego rozwiązania z implementacją Hibernate.

EDYCJA : Wygląda na to, że JPA 2.0 będzie to obsługiwać.

Paul Whelan
źródło

Odpowiedzi:

164

Jeśli używasz go z Hibernate, będziesz musiał jawnie zdefiniować adnotację CascadeType.DELETE_ORPHAN, której można używać w połączeniu z JPA CascadeType.ALL.

Jeśli nie planujesz używać Hibernacji, musisz najpierw jawnie usunąć elementy podrzędne, a następnie usunąć główny rekord, aby uniknąć jakichkolwiek osieroconych rekordów.

sekwencja wykonania

  1. pobierz główny wiersz do usunięcia
  2. pobierz elementy potomne
  3. usuń wszystkie elementy podrzędne
  4. usuń główny wiersz
  5. Zamknij sesję

W przypadku JPA 2.0 można teraz używać opcji orphanRemoval = true

@OneToMany(mappedBy="foo", orphanRemoval=true)
Varun Mehta
źródło
3
dzięki Skończyło się na tym, że jechałem tą trasą, myślę, że to trochę przesadna specyfikacja JPA.
Paul Whelan,
13
Standard JPA 2.0 ma teraz deleteOrphan jako atrybut @OneToMany Jeśli używasz najnowszej hibernacji, możesz zrobić @OneToMany (..., deleteOrphan = true)
jomohke
jaka jest sekwencja wykonywania, gdy po prostu aktualizuję elementy podrzędne? czy dokumenty osierocone zostaną usunięte?
jAckOdE
113

Jeśli używasz JPA 2.0, możesz teraz używać orphanRemoval=trueatrybutu pliku@xxxToMany adnotacji, aby usunąć sieroty.

W rzeczywistości CascadeType.DELETE_ORPHANzostał wycofany w wersji 3.5.2-Final.

Kango_V
źródło
6
Właściwie uważam, że orphanRemoval = true oznacza coś innego, tj. Usunięcie obiektu, gdy usuwam go z kolekcji jego rodzica. Zobacz download.oracle.com/javaee/6/tutorial/doc/bnbqa.html#giqxy
Archie
Proszę przejść przez link Archiego.
Jigar Shah,
4
orphanRemoval = true też nie działa. Trzeba to zrobić w stary sposób.
Joe Almore
45
╔═════════════╦═════════════════════╦═════════════════════╗
   Action      orphanRemoval=true    CascadeType.ALL   
╠═════════════╬═════════════════════╬═════════════════════╣
   delete         deletes parent      deletes parent   
   parent         and orphans         and orphans      
╠═════════════╬═════════════════════╬═════════════════════╣
   change                                              
  children      deletes orphans         nothing        
    list                                               
╚═════════════╩═════════════════════╩═════════════════════╝
Sergii Szewczyk
źródło
1
Co się stanie, jeśli mam cascade = CascadeType.ALL, orphanRemoval = falsei usunę rodzica? Czy usunie dzieci, mimo że wyraźnie zabroniłem?
izogfif
7

możesz użyć @PrivateOwned, aby usunąć sieroty, np

@OneToMany(mappedBy = "masterData", cascade = {
        CascadeType.ALL })
@PrivateOwned
private List<Data> dataList;
reshma
źródło
5
Dzięki @reshma, należy zauważyć, że @PrivateOwned to rozszerzenie JPA eclipselink.
Paul Whelan,
5

Po prostu znajduję to rozwiązanie, ale w moim przypadku nie działa:

@OneToMany(cascade = CascadeType.ALL, targetEntity = MyClass.class, mappedBy = "xxx", fetch = FetchType.LAZY, orphanRemoval = true) 

orphanRemoval = true nie ma żadnego efektu.

Valéry Stroeder
źródło
1
Musiałem wyczyścić i zbudować, zanim zmiana weszła w życie.
maralbjo
Wow, od godziny zastanawiałem się, dlaczego dodanie CascadeType.ALL na moim ManyToOne nie było kaskadowym usuwaniem. Oczyszczone, zbudowane i działa. Dzięki @maralbjo.
Andrew Mairose
2

Miałem ten sam problem i zastanawiałem się, dlaczego ten warunek poniżej nie usuwa sierot. Lista potraw nie została usunięta w Hibernate (5.0.3.Final), kiedy wykonałem nazwane zapytanie o usunięcie:

@OneToMany(mappedBy = "menuPlan", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Dish> dishes = new ArrayList<>();

Wtedy przypomniałem sobie, że nie wolno mi używać nazwanego zapytania usuwającego , ale EntityManager. Ponieważ użyłem tej EntityManager.find(...)metody, aby pobrać jednostkę, a następnie EntityManager.remove(...)ją usunąć, naczynia również zostały usunięte.

Bevor
źródło
2

Właśnie @OneToMany(cascade = CascadeType.ALL, mappedBy = "xxx", fetch = FetchType.LAZY, orphanRemoval = true) .

Usuń targetEntity = MyClass.class , działa świetnie.

Kohan95
źródło
1

Dla dokumentacji, w OpenJPA przed JPA2 było to @ElementDependant.

Simone Gianni
źródło
0

Używałem mapowania jeden do jednego, ale dziecko nie było usuwane. JPA powodowało naruszenie klucza obcego

Po użyciu orphanRemoval = true problem został rozwiązany

vipin chauhan
źródło
@OneToOne (cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn (name = "CHILD_OID") private Child child;
vipin chauhan