2014-07-04 11 views
7

Sto tentando di utilizzare orphanRemoval negli oggetti Hibernate 4.3.5/JPA2 ma non sembra funzionare come previsto. Non sono sicuro, tuttavia, se sto facendo qualcosa di sbagliato, o se questo è ancora un bug in Hibernate.La rimozione di JPA 2/Hibernate per orfani non funziona ancora con @OneToMany?

Dati i seguenti rapporti (@Version, getter e setter omesse per brevità):

@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; 
} 

Mi aspetterei che se rimuovere un contratto dalla lista Provider.contracts, che sarebbe eliminare le righe corrispondenti da la tabella del contratto e tutti gli allegati associati dalla tabella degli allegati. Tuttavia, viene cancellata solo la tabella del contratto. La tabella degli allegati non è stata modificata.

Es:

// 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; 
     } 
    } 

Dato che gli attacchi siano ManyToOne rispetto alla tavola contratto, se il contratto è cancellato, quindi gli allegati sono orfani. Ma anche con lo orphanRemoval=true, questo non cancella le righe dal DB.

Ho trovato diversi problemi relativi a questo per Hibernate 3 (sia qui su SO, sia su Jira e altrove online), ma avevo capito che era stato risolto in Hibernate 4. Ma usando Hibernate 4.3.5 lo vedo ancora problema. Da this issue, sembra funzionare, quindi non sono sicuro del motivo per cui non riesco a farlo funzionare.

C'è qualcosa di sbagliato/mancante nel mio codice o Hibernate è ancora problematico? Devo implementare equals e hashCode in una qualsiasi di queste classi di entità affinché orphanRemoval funzioni correttamente? Ho provato ad implementare entrambi i metodi in Contratto e Allegato, ma non ho fatto alcuna differenza.

Guardando i log di Hibernate, mostra Hibernate che apporta le modifiche alla tabella di join (o mappatura FK), ma in realtà non elimina la riga dalla tabella associata. Posso vedere Hibernate che imposta provider_id = null nella tabella del contratto, ma non dovrebbe invece eliminare la riga del contratto?

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] 

risposta

6

Onestamente, non so perché, ma se si aggiunge CascadeType.PERSIST (o meglio CascadeType.ALL) per il vostro rapporto @OneToMany in Provider entità che funzionerà come previsto.

Probabilmente la documentazione di Hibernate è carente in questo piccolo dettaglio.

aggiornamento EclipseLink 2.5.1 con JPA2 non sembrano avere questo problema

2 ° aggiornamento

Nella sezione 2.9, entità relazioni, la specifica JPA 2.1 dice: "Se il l'entità che è orfana è un'entità distaccata, nuova o rimossa, la semantica di orphanRemoval non si applica. "

Non so se i vostri relativi soggetti sono staccati, ma se sì, allora non è un bug :)

+0

Ho provato ad aggiornare l'entità con il 'CascadeType.ALL', ma ancora non funziona. –

+1

@EricB. Hai impostato '@OneToMany (orphanRemoval = true, cascade = CascadeType.ALL)' su 'Lista contratti;'? Qui, con Hibernate 4.3.5.Final e jpa-api-2.1 funziona bene. Rimuove le entità 'contract_attachment',' Attachment' e 'Contract' dal DB. –

+0

Ho fatto una pulizia completa, e infatti, 'CascadeType.ALL' o' CascadeType.PERSIST' sembra funzionare. Tuttavia, il problema è che non voglio fare un 'CascadeType.PERSIST'! Dovrebbe 'orphanRemoval' non essere indipendente da una cascata persistere? –

-3

Inoltre sto ottenendo il problema dichiarato.Anche se è stato deprecato, il sotto uso funziona bene con la rimozione di orfani:

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

CascadeType.DELETE_ORPHAN non esiste in ibernazione 4 sembra – cproinger

+0

No, non funziona e inoltre org.hibernate.annotations.CascadeType.DELETE_ORPHAN è deprecato – mehdi

Problemi correlati