Eliminazione JPA con 2 classi di entità interbloccate
Domanda
Ho 2 bean di entità 3 EJB:
@Entity
public class Organisation
{
@Id
@Column(length = 64)
private String guid;
private String name;
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
@JoinColumn(name = "home_unit_fk", nullable = true)
private Unit homeUnit;
}
@Entity
public class Unit
{
@Id
@Column(length = 64)
private String guid;
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "organisation_fk", nullable = false)
private Organisation organisation;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_unit_fk", nullable = true)
private Unit parentUnit;
@OneToMany(mappedBy = "parentUnit", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
@OrderBy("shortName")
@OptimisticLock(excluded = true)
private Set<Unit> childUnits;
}
Se faccio una cancellazione sull'organizzazione usando lo standard Dao:
public int deleteByGuid(final String guid)
{
final Query query = entityManager.createQuery("delete from " + getPersistentClass().getName() + " where guid = :guid");
query.setParameter("guid", guid);
return query.executeUpdate();
}
Ma ottengo la seguente eccezione:
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: impossibile eliminare o aggiornare una riga principale: un vincolo di chiave esterna non riesce ( config
. unità
, CONSTRAINT FK27D184F5D4393D
CHIAVE ESTERA ( organisation_fk
) RIFERIMENTI organizzazione
( guid
))
Non capisco. Che cosa sto facendo di sbagliato? JPA / Hibernate non dovrebbero eseguire cancellazioni sia sull'unità che sull'organizzazione all'interno della stessa transazione?
Soluzione
Una query di eliminazione in blocco non carica gli oggetti in memoria e ignora qualsiasi cascata specificata nelle associazioni.
Vorrei codificare il metodo di eliminazione come:
public int deleteByGuid(final String guid){
Organization org = entityManager.find(Organization.class, guid);
entityManager.remove(org);
}
Se si utilizza una query per eseguire aggiornamenti in blocco, l'operazione viene delegata direttamente al database. Se desideri eliminare oggetti figlio, devi impostare un trigger DELETE CASCADE sul "database" " livello.
Caricando l'oggetto e rimuovendolo, Hibernate attiverà la cascata sull'oggetto " oggetto " livello.
Maggiori informazioni disponibili su: http://twasink.net/blog/2005/04/differences-in-behaviour-b Between-hibernate-delete-queries-and-the-old-way/