Suppression JPA avec 2 classes d'entités imbriquées
Question
J'ai 2 beans entité EJB 3:
@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 je supprime l'organisation avec la norme 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();
}
Mais j'obtiens l'exception suivante:
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: impossible de supprimer ou de mettre à jour une ligne parente: une contrainte de clé étrangère échoue ( config
. unité
, CONSTRAINT FK27D184F5D4393D
CLÉ ÉTRANGÈRE ( organisation_fk
) RÉFÉRENCES organisation
( guid
))
Je ne comprends pas. Qu'est-ce que je fais mal? JPA / Hibernate ne devrait-il pas effectuer des suppressions à la fois sur l'unité et sur l'organisation au sein d'une même transaction?
La solution
Une requête de suppression en bloc ne charge pas les objets en mémoire et contourne les cascades spécifiées dans les associations.
Je coderais votre méthode de suppression comme suit:
public int deleteByGuid(final String guid){
Organization org = entityManager.find(Organization.class, guid);
entityManager.remove(org);
}
Si vous utilisez une requête pour effectuer des mises à jour en masse, l'opération est déléguée directement à la base de données. Si vous souhaitez supprimer des objets enfants, vous devez définir un déclencheur DELETE CASCADE dans la base de données " base de données " niveau.
En chargeant et en supprimant l'objet, Hibernate déclenchera la cascade au niveau de "l'objet". niveau.
Plus d'informations disponibles sur: http://twasink.net/blog/2005/04/differences-in-behaviour-between-hibernate-delete-queries-and-the-old-way/