#java #spring-boot #foreign-keys #many-to-many
#java #spring-boot #внешние ключи #многие ко многим
Вопрос:
Я пытаюсь удалить некоторые записи из своей базы данных, но получаю следующую ошибку: «обновление или удаление в таблице «роль» нарушает ограничение внешнего ключа «fk3qjq7qsiigxa82jgk0i0wuq3g» в таблице «users_role» «
Я провел некоторое исследование и обнаружил, что это может иметь какое-то отношение к тому, что для одного из моих отношений установлено значение @ManyToMany .
Я пытался модифицировать свой код из других примеров на этом сайте, но безуспешно.
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "users_id")
private long id;
@Column(name = "email")
@Email(message = "*Please provide a valid Email")
@NotEmpty(message = "*Please provide an email")
private String email;
@Column(name = "password")
@Length(min = 5, message = "*Your password must have at least 5 characters")
@NotEmpty(message = "*Please provide your password")
private String password;
@Column(name = "name")
@NotEmpty(message = "*Please provide your name")
private String name;
@Column(name = "surname")
@NotEmpty(message = "*Please provide your surname")
private String surname;
@Column(name = "active")
private int active;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "users_role", joinColumns = @JoinColumn(name = "users_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles;
@Column(name = "position")
private String position;
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "role_id")
private int id;
public class UserController {
.
.
.
.
@GetMapping("/admin/deleteuser/{id}")
public String deleteUser(@PathVariable("id") long id, Model model) {
User user = userRepository.findById(Long.valueOf(id)).orElseThrow(() -> new IllegalArgumentException("Invalid user Id:" id));
userRepository.delete(user);
model.addAttribute("users", userRepository.findAll());
return "/admin/show-users";
}
Ответ №1:
Проблема, похоже, здесь:
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "users_role", joinColumns = @JoinColumn(name = "users_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles;
В частности, CascadeType.ALL
означает, что при попытке удалить User
это удаление будет каскадно связано с ролями этого User
. Маловероятно, что вы этого хотите, поскольку весь смысл создания отношения «многие ко многим» вместо «один ко многим» заключался бы в том, что более одного пользователя могут иметь определенную роль. Если вы попытаетесь удалить роль (напрямую или через каскадное удаление), тогда есть две альтернативы:
- удаление каскадом распространяется на всех других пользователей, имеющих ту же роль (а затем обратно на роли всех этих пользователей, и т.д.., Или
- удаление завершается неудачей.
Вы видите (2). Конкретное сообщаемое нарушение ограничения связано со строками других пользователей в user_role
таблице при попытке удалить роли.
Мне неясно, действительно ли вы хотите каскадировать какие-либо операции сохранения от User
s к их назначенным Role
s. Я склонен думать, что нет, и в этом случае вам вообще не нужно указывать cascade
атрибут вашего ManyToMany
:
@ManyToMany
@JoinTable(name = "users_role", joinColumns = @JoinColumn(name = "users_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles;
Однако, если вы используете каскад, вам нужно указать отдельные типы каскадов, которые вы хотите, опустив CascadeType.REMOVE
, может быть, что-то вроде
@ManyToMany(cascade = {CascadeType.DETACH, CascadeType.REFRESH})
@JoinTable(name = "users_role", joinColumns = @JoinColumn(name = "users_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles;