У меня проблема с ошибкой ограничения, когда я каскадно удаляю сущность, которая ссылается на другую сущность.
Я использую Hibernate в качестве провайдера JPA.
Домен модель:
![ERD](https://i.stack.imgur.com/DpcLA.png)
- Каждый
Zone
может иметь больше Actions
, но Actions
не распределяются между Zones
( OneToMany ). TeleportAction
(один из возможных видов Action
) содержит набор Zones
в качестве целей. Каждый TeleportAction
может иметь больше Zones
в качестве целей и Zones
, и они могут использоваться несколькими TeleportActions
( ManyToMany ).
Как работает удаление
- Я звоню
ZoneManager.deleteZone(zone)
- ZoneManager сначала проходит через все
Zones
и их TeleportActions
и удаляет удаленные Zone
из своих целей. - После этого ZoneManager удаляет
Zone
из списка Zones
- Затем я удаляю
Zone
из БД с помощью Hibernate через session.delete(zone)
. Эта операция распространяется на Actions
. - Элемент списка
Сначала вызывается ZoneManager.deleteZone(zone)
, который работает так:
public void deleteZone(Zone removedZone) {
// Remove this zone from all TeleportActions
for (Zone zone : zones) {
for (Action action : zone.getActions()) {
if (action instanceof TeleportAction) {
((TeleportAction)action).removeTarget(removedZone);
}
}
}
// Finally remove zone
zones.remove(removedZone);
}
, затем вызывающая сторона удаляет Zone
из БД. Я хочу, чтобы Hibernate автоматически подтвердил, что я удалил эту Zone
из Action
целей.
session.delete(removedZone);
Ошибка, которую я получаю
Hibernate: /* delete cz.iwitrag.greencore.gameplay.zones.Zone */ delete from gcore_Zone where id=?
[org.hibernate.engine.jdbc.spi.SqlExceptionHelper] SQL Error: 1451, SQLState: 23000
[org.hibernate.engine.jdbc.spi.SqlExceptionHelper] Cannot delete or update a parent row: a foreign key constraint fails (`309145_mysql_db`.`gcore_tpaction_targetzones`, CONSTRAINT `FK4rvpdg8xjyt6lk5281jbi78c5` FOREIGN KEY (`targetZone_id`) REFERENCES `gcore_Zone` (`id`))
[org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl] HHH000010: On release of batch it still contained JDBC statements
javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
...
Эта ошибка вызвана тем, что когда я удалите Zone
, это все еще цель некоторых TeleportActions
.
Даже если я удалил это Zone
из TeleportAction's
целей в бизнес-коде до вызова session.delete(zone)
, Hibernate не подтверждает это и не удаляет Zone
из ManyToMany ассоциации.
Entities
Zone
, который имеет список Actions
@Entity
public class Zone {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", updatable = false, nullable = false)
private Long id;
@OneToMany(fetch = FetchType.EAGER, orphanRemoval = true)
@Cascade(CascadeType.ALL)
@OrderColumn(name = "list_id")
@JoinColumn(name = "zone_id")
private List<Action> actions = new ArrayList<>();
...
}
Action
, который является суперклассом TeleportAction
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "actionType")
public abstract class Action {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", updatable = false, nullable = false)
private Long id;
...
}
TeleportAction
, который содержит Набор Zones
в качестве целей телепортации.
Обратите внимание, что это отношение отличается от Zone->Action
отношения.
@Entity
@DiscriminatorValue("tp")
public class TeleportAction extends Action {
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "tpaction_targetzones", joinColumns = @JoinColumn(name="tpAction_id"), inverseJoinColumns = @JoinColumn(name="targetZone_id"))
private Set<Zone> targets = new HashSet<>();
...
}
Вопрос
Как заставить Hibernate автоматически удалить удалено Zone
из таблицы tpaction_targetzones
перед тем, как он действительно удалит Zone
из базы данных, чтобы избежать ошибки ограничения внешнего ключа?