JPA Excluir com 2 Classes de bloqueio de entidade
Pergunta
Eu tenho 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;
}
Se eu fizer uma exclusão na organização usando Dao padrão:
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();
}
Mas eu recebo a seguinte exceção:
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Não é possível excluir ou atualizar uma linha pai: a restrição de chave estrangeira falhar (config
.unit
, CONSTRAINT FK27D184F5D4393D
FOREIGN KEY (organisation_fk
) Referências organisation
(guid
))
Eu não entendo. O que estou fazendo de errado? JPA / Hibernate não deve executar exclusões em ambos da Unidade e da Organização dentro da mesma transação?
Solução
A consulta de exclusão em massa não carregar objetos na memória e ignora qualquer cascata especificado em associações.
Gostaria de codificar seu método de exclusão como:
public int deleteByGuid(final String guid){
Organization org = entityManager.find(Organization.class, guid);
entityManager.remove(org);
}
Se você usar uma consulta para fazer atualizações em massa, a operação é delegada ao banco de dados diretamente. Se você deseja excluir objetos filho, você tem que definir um gatilho DELETE CASCADE no nível de "banco de dados".
Ao carregar o objecto e a sua remoção, hibernação irá desencadear a cascata no nível "objecto".
Mais informações disponíveis em: http://twasink.net/blog/2005/04/differences-in-behaviour-between-hibernate-delete-queries-and-the-old-way/