Eliminar JPA con 2 clases de entidad de enclavamiento
Pregunta
Tengo 2 EJB 3 Entity Beans:
@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;
}
Si hago una eliminación en la Organización usando Dao estándar:
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();
}
Pero obtengo la siguiente excepción:
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: No se puede eliminar ni actualizar una fila principal: falla una restricción de clave externa ( config
. unit
, CONSTRAINT FK27D184F5D4393D
FOREIGN KEY ( organisation_fk
) REFERENCIAS organización
( guid
))
No lo entiendo. ¿Qué estoy haciendo mal? ¿No debería JPA / Hibernate realizar eliminaciones tanto en la Unidad como en la Organización dentro de la misma transacción?
Solución
Una consulta de eliminación masiva no carga objetos en la memoria y pasa por alto cualquier cascada especificada en las asociaciones.
Codificaría tu método de eliminación como:
public int deleteByGuid(final String guid){
Organization org = entityManager.find(Organization.class, guid);
entityManager.remove(org);
}
Si utiliza una consulta para realizar actualizaciones masivas, la operación se delega directamente a la base de datos. Si desea eliminar objetos secundarios, debe configurar un desencadenador DELETE CASCADE en la base de datos " " nivel.
Al cargar el objeto y eliminarlo, Hibernate activará la cascada en el objeto " " nivel.
Más información disponible en: http://twasink.net/blog/2005/04/differences-in-behaviour-between-hibernate-delete-queries-and-the-old-way/