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]
Ho provato ad aggiornare l'entità con il 'CascadeType.ALL', ma ancora non funziona. –
@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. –
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? –