Удаление JPA с двумя взаимосвязанными классами сущностей
Вопрос
У меня есть 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;
}
Если я удалю организацию, используя стандартный 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();
}
Но я получаю следующее исключение:
com.mysql.jdbc.Exceptions.jdbc4.MySQLIntegrityConstraintViolationException:Невозможно удалить или обновить родительскую строку:ограничение внешнего ключа не выполнено (config
.unit
, ОГРАНИЧЕНИЕ FK27D184F5D4393D
ВНЕШНИЙ КЛЮЧ (organisation_fk
) ИСПОЛЬЗОВАННАЯ ЛИТЕРАТУРА organisation
(guid
))
Я этого не понимаю.Что я делаю не так?Разве JPA/Hibernate не должен выполнять удаление как для подразделения, так и для организации в рамках одной транзакции?
Решение
Запрос на массовое удаление не загружает объекты в память и обходит любой каскад, указанный в ассоциациях.
Я бы закодировал ваш метод удаления как:
public int deleteByGuid(final String guid){
Organization org = entityManager.find(Organization.class, guid);
entityManager.remove(org);
}
Если вы используете запрос для выполнения массовых обновлений, операция делегируется непосредственно базе данных.Если вы хотите удалить дочерние объекты, вам необходимо установить триггер DELETE CASCADE на уровне «базы данных».
Загрузив объект и удалив его, Hibernate запустит каскад на уровне «объекта».
Дополнительная информация доступна по адресу: http://twasink.net/blog/2005/04/differences-in-behaviour-between-hibernate-delete-queries-and-the-old-way/