Как исправить «нарушает ограничение внешнего ключа» в Spring-Boot при попытке удалить запись. Использование @ManyToMany - PullRequest
0 голосов
/ 02 апреля 2019

Я пытаюсь удалить некоторые записи из моей базы данных, но получаю следующую ошибку: «Роль обновления или удаления в таблице» нарушает ограничение внешнего ключа «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 Ответ

0 голосов
/ 02 апреля 2019

Проблема, кажется, здесь:

    @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. Весьма маловероятно, что вы захотите, чтобы весь смысл установления отношений «многие ко многим», а не «один ко многим», заключался в том, что нескольким пользователям может быть присвоена определенная роль. Если вы попытаетесь удалить роль (напрямую или через каскадное удаление), то есть две альтернативы:

  1. удаление распространяется на всех других пользователей, имеющих ту же роль (а затем обратно на все эти роли пользователей, и т. Д. ., Или
  2. удаление не удалось.

Вы видите (2). Конкретное сообщение о нарушении ограничения связано с строками других пользователей в таблице user_role при попытке удалить роли.

Мне неясно, действительно ли вы хотите каскадно любых операций персистентности от User с до назначенных им Role с. Я склонен не думать, в этом случае вам вообще не нужно указывать атрибут 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;
...