2014-07-04 10 views
7

Próbuję użyć obiektu osieroconego w obiektach Hibernuj 4.3.5/JPA2, ale wygląda na to, że nie działa zgodnie z oczekiwaniami. Nie jestem jednak pewien, czy robię coś niepoprawnego, czy też nadal jest to błąd w Hibernate.JPA 2/Hibernate usunięcie sieroty nadal nie działa z @OneToMany?

Biorąc pod uwagę następujące zależności (@version, pobierające i ustawiające pominięty dla zwięzłość):

@Entity 
public class Provider implements Serializable { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(name = "id") 
    private Long id; 

    private String name; 

    @OneToMany(orphanRemoval=true,cascade=CascadeType.REMOVE) 
    @JoinColumn(name="provider_id", referencedColumnName="id") 
    private List<Contract> contracts; 
} 


@Entity 
public class Contract implements Serializable { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(name = "id") 
    private Long id; 

    private String volume; 

    @OneToMany(orphanRemoval=true,cascade=CascadeType.REMOVE) // delete any attachments that were previously uploaded with this contract 
    @JoinTable(name="contract_attachment", joinColumns = @JoinColumn(name = "contract_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "attachment_id", referencedColumnName = "id")) 
    private List<Attachment> attachments; 
} 

@Entity 
public class Attachment implements Serializable { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(name = "id") 
    private Long id; 

    private String filename; 
} 

Spodziewam się, że jeśli usunąć umowę z listy Provider.contracts, że będzie usunąć odpowiednie wiersze z tabela kontraktów i wszystkie powiązane załączniki z tabeli załączników. Jednak tylko tabela umowy zostanie usunięta. Tabela załączników nie jest modyfikowana.

Ex:

// loop over all contracts and delete the one with the matching id 
    for(Iterator<Contract> it = provider.getContracts().iterator(); it.hasNext();){ 
     Contract c = it.next(); 
     if(c.getId() == contractId){ 
      it.remove(); 
      break; 
     } 
    } 

Zważywszy, że załączniki są ManyToOne stosunku do tabeli zamówienia, jeżeli umowa została usunięta, wówczas załączniki są sierotami. Ale nawet z orphanRemoval=true nie usuwa to wierszy z DB.

Znalazłem kilka problemów związanych z tym dla Hibernate 3 (zarówno tutaj na SO, i Jira i gdzie indziej w Internecie), ale zrozumiałem, że został naprawiony w Hibernate 4. Ale używając Hibernate 4.3.5 nadal widzę to kwestia. Od this issue, wydaje się, że działa, więc nie jestem pewien, dlaczego nie mogę go uzyskać funkcjonalny.

Czy coś jest nie tak/brakuje w moim kodzie lub czy problem z Hibernowaniem jest nadal problematyczny? Czy wymagana jest implementacja equals i hashCode w którejkolwiek z tych klas jednostek, aby orphanRemoval działał poprawnie? Próbowałem implementować obie metody w Kontrakcie i Załączniku, ale nie zrobiłem żadnej różnicy.

Patrząc na logi Hibernacji, pokazuje Hibernate dokonując zmian w tabeli łączenia (lub odwzorowaniu FK), ale tak naprawdę nie usuwa wiersza z powiązanej tabeli. Widzę ustawienie Hibernuj ustawienie provider_id = null w tabeli kontraktu, ale czy nie powinno to usuwać wiersz zamówienia?

2014-07-04 15:06:41,333 [main] [-] DEBUG org.hibernate.SQL - 
    /* update 
     com.ia.domain.Provider */ update 
      provider 
     set 
      default_contact_id=?, 
      name=?, 
      type=?, 
      version=?, 
      website=? 
     where 
      id=? 
      and version=? 
Hibernate: 
    /* update 
     com.ia.domain.Provider */ update 
      provider 
     set 
      default_contact_id=?, 
      name=?, 
      type=?, 
      version=?, 
      website=? 
     where 
      id=? 
      and version=? 
2014-07-04 15:06:41,334 [main] [-] TRACE hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - [null] 
2014-07-04 15:06:41,334 [main] [-] TRACE hibernate.type.descriptor.sql.BasicBinder - binding parameter [2] as [VARCHAR] - [name_3] 
2014-07-04 15:06:41,335 [main] [-] TRACE org.hibernate.type.EnumType - Binding [CARRIER] to parameter: [3] 
2014-07-04 15:06:41,336 [main] [-] TRACE hibernate.type.descriptor.sql.BasicBinder - binding parameter [4] as [INTEGER] - [2] 
2014-07-04 15:06:41,336 [main] [-] TRACE hibernate.type.descriptor.sql.BasicBinder - binding parameter [5] as [VARCHAR] - [website_3] 
2014-07-04 15:06:41,337 [main] [-] TRACE hibernate.type.descriptor.sql.BasicBinder - binding parameter [6] as [BIGINT] - [4] 
2014-07-04 15:06:41,338 [main] [-] TRACE hibernate.type.descriptor.sql.BasicBinder - binding parameter [7] as [INTEGER] - [1] 
2014-07-04 15:06:41,342 [main] [-] DEBUG org.hibernate.SQL - 
    /* delete one-to-many com.ia.domain.Provider.contracts */ update 
      contract 
     set 
      provider_id=null 
     where 
      provider_id=? 
Hibernate: 
    /* delete one-to-many com.ia.domain.Provider.contracts */ update 
      contract 
     set 
      provider_id=null 
     where 
      provider_id=? 
2014-07-04 15:06:41,344 [main] [-] TRACE hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - [4] 

Odpowiedz

6

Szczerze mówiąc, nie wiem dlaczego, ale jeśli dodać CascadeType.PERSIST (lub lepiej CascadeType.ALL) do relacji @OneToMany w Provider podmiot będzie działać zgodnie z oczekiwaniami.

Prawdopodobnie w tym małym szczególe brakuje dokumentacji Hibernate.

aktualizacja EclipseLink 2.5.1 z JPA2 wydaje się nie mieć tej kwestii

2-ty aktualizacja

W rozdziale 2.9, podmiot Relacje, JPA 2.1 Spec mówi: „Jeśli istota osierocona jest jednostką odłączoną, nową lub usuniętą, semantyka sierocińca odwrotnego nie ma zastosowania. "

Nie wiem, jeśli podmioty powiązane są odłączane, ale jeśli tak, to nie jest to błąd :)

+0

Próbowałem aktualizacji podmiotu z 'CascadeType.ALL', ale nadal nie działa. –

+1

@EricB. Czy ustawiłeś '@OneToMany (orphanRemoval = true, cascade = CascadeType.ALL)' na listach 'List ; '? Tutaj, z Hibernate 4.3.5.Final i jpa-api-2.1 działa dobrze. Usuwa elementy 'contract_attachment',' Attachment' oraz 'Contract' z DB. –

+0

Zrobiłem pełny czysty, i rzeczywiście, 'CascadeType.ALL' lub' CascadeType.PERSIST' wydaje się działać. Jednak problem polega na tym, że nie chcę wykonywać 'CascadeType.PERSIST'! Czy 'orphanRemoval' nie powinien być niezależny od kaskady? –

-3

Jestem również coraz problem inaczej.Chociaż został przestarzały, poniżej użycie działa dobrze z usunięciem sierot:

@org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN) 
+0

CascadeType.DELETE_ORPHAN nie istnieje w hibernacji 4 wydaje się, że – cproinger

+0

Nie to nie jest zadaniem, a ponadto org.hibernate.annotations.CascadeType.DELETE_ORPHAN jest przestarzałe – mehdi

Powiązane problemy