JPA @ManyToMany - Не удается удалить или обновить родительскую строку: ограничение внешнего ключа не удается
У меня есть сущности:
@Entity
public class User {
@ManyToMany(cascade=CascadeType.PERSIST, fetch=FetchType.EAGER)
private List<Role> roles = new ArrayList<Role>();
@Entity
public class Role {
@ManyToMany(cascade=CascadeType.PERSIST, fetch=FetchType.EAGER)
private Set<Permission> permissions = new HashSet<Permission>();
При выполнении удаления/удаления создается следующее исключение:
Caused by: com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`user_role`, CONSTRAINT `FK_USER_ROLE_roles_ID` FOREIGN KEY (`roles_ID`) REFERENCES `role` (`ID`))
Кажется, что есть проблема с сгенерированной таблицей соединений и внешними ключами.
Как это можно устранить, чтобы роль могла быть удалена?
Edit:
Экспортированный SQL показывает это:
CREATE TABLE IF NOT EXISTS `user_role` (
`User_ID` bigint(20) NOT NULL,
`roles_ID` bigint(20) NOT NULL,
PRIMARY KEY (`User_ID`,`roles_ID`),
KEY `FK_USER_ROLE_roles_ID` (`roles_ID`)
)
Ответы
Ответ 1
Подумайте, как JPA разрешит отношения "многие ко многим".
Я предполагаю, что он создает таблицу User
, таблицу Role
и таблицу user_role
, которая содержит ссылки (внешние ключи) для пользователя и для роли.
Теперь, если вы хотите удалить роль, вам нужно удалить все ссылки этой роли, которые хранятся пользователями. Для этого вам нужно перебрать всех пользователей, которые имеют такую роль, и удалить их из этого списка ролей пользователя. Затем вы можете безопасно удалить роль.
Кстати, как только вы решите эту проблему, у вас, вероятно, будет следующая с Permission
. Итак, если бы я был вами, я бы временно удалил поле permissions
из Role
, чтобы сделать работу с ролью, а затем восстановить permissions
только для единственных новых проблем, если они существуют.
Ответ 2
Попробуйте добавить CascadeType.REMOVE
к вашим сопоставлениям:
@ManyToMany(cascade= {CascadeType.PERSIST, CascadeType.REMOVE}, fetch=FetchType.EAGER)
private List<Role> roles = new ArrayList<Role>();
@ManyToMany(cascade= {CascadeType.PERSIST, CascadeType.REMOVE}, fetch=FetchType.EAGER)
private Set<Permission> permissions = new HashSet<Permission>();
Таким образом, дочерние объекты не должны удаляться перед родителем, поэтому вы можете удалить роль, не удаляя ранее ее разрешения.
Ответ 3
Я исправил это,
изменение некоторых имен таблиц (может быть, эти имена были зарезервированными словами в MySQL?)
Например: "администраторы" вместо "администратор"
@Table(name = "admins")
public class Admin extends TrackedEntity {
}
и путем изменения:
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
за:
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
в приложении. свойства