Отношение ManyToMany удаляет все сущности - PullRequest
0 голосов
/ 20 июня 2019

У меня есть две сущности, пользователь и фильмы. Это множество двусторонних отношений. Моя проблема в том, что когда я удаляю фильм через мой контроллер, он также удаляет все связанные с этим сущности фильма. Мой пользователь и этот пользователь роли и сущность фильма. Что мне нужно сделать, чтобы избавиться от сущности фильма из таблицы при ее удалении и сохранить пользователя с его ролями вместо того, чтобы удалять их все.

@Data
@ToString
@EqualsAndHashCode
@Entity
@Table(name = "movies")
public class Movie {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name = "title")
    private String title;
    @Column(name = "description")
    private String description;
    @Column(name = "release_date")
    @Temporal(TemporalType.DATE)
    private Date release_date;
    @Column(name = "country")
    private String country;
    @Column(name = "category")
    private String category;
    @ManyToMany(mappedBy = "movies")
    @ToString.Exclude
    @EqualsAndHashCode.Exclude
    private Set<User> users = new HashSet<>();

@Data
@ToString
@Entity
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name = "username")
    private String username;
    @Column(name = "password")
    private String password;
    @Transient
    private String confirmPassword;
    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name = "users_roles", joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
            inverseJoinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "id")})
    @ToString.Exclude
    @EqualsAndHashCode.Exclude
    private Set<Role> roles = new HashSet<>();

    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name = "users_movies", joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
            inverseJoinColumns = {@JoinColumn(name = "movie_id", referencedColumnName = "id")})
    @ToString.Exclude
    @EqualsAndHashCode.Exclude
    private Set<Movie> movies = new HashSet<>();

Ответы [ 3 ]

0 голосов
/ 21 июня 2019

Ну, я должен был догадаться, как выглядит ваша Role сущность, поэтому приведу полные примеры. Вы не указали, используете ли вы Spring-Data-Jpa или просто Jpa, так что кто знает. Отредактируйте: в своих примерах вы наконец-то пояснили, что используете spring-data-jpa, но в любом случае понятия те же, что и здесь.

@Data
@ToString
@Entity
@Table(name = "roles")
public class Role {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToMany(mappedBy="roles")
    @ToString.Exclude
    @EqualsAndHashCode.Exclude
    private Set<User> users = new HashSet<>();

}

и использовать

tx.begin();

User u1 = new User();
Role r1 = new Role();
u1.setRoles(Collections.singleton(r1));
Movie m1 = new Movie();
m1.setDescription("movie 1");
Movie m2 = new Movie();
m2.setDescription("movie 2");
u1.setMovies(Stream.of(m1, m2).collect(Collectors.toSet()));
em.persist(u1);

tx.commit();

// now to query
em.clear();

tx.begin();
User u = em.createQuery("from User u left outer join fetch u.movies where u.id = 1", User.class).getSingleResult();
Movie m = u.getMovies().stream().filter(mv->mv.getDescription().equals("movie 1")).findFirst().get();
u.getMovies().remove(m);
em.remove(m);
tx.commit();

и это создает журнал

create table users (id bigint generated by default as identity (start with 1), password varchar(255), username varchar(255), primary key (id))
create table users_movies (user_id bigint not null, movie_id bigint not null, primary key (user_id, movie_id))
create table users_roles (user_id bigint not null, role_id bigint not null, primary key (user_id, role_id))
alter table users_movies add constraint FKt4hasm7tvj0vor58ql33xptjy foreign key (movie_id) references movies
alter table users_movies add constraint FKhhj9vi206o88q0typfntk3fek foreign key (user_id) references users
alter table users_roles add constraint FKj6m8fwv7oqv74fcehir1a9ffy foreign key (role_id) references roles
alter table users_roles add constraint FK2o0jvgh89lemvvo17cbqvdxaa foreign key (user_id) references users
insert into users (id, password, username) values (default, ?, ?)
insert into movies (id, category, country, description, release_date, title) values (default, ?, ?, ?, ?, ?)
insert into movies (id, category, country, description, release_date, title) values (default, ?, ?, ?, ?, ?)
insert into roles (id) values (default)
insert into users_movies (user_id, movie_id) values (?, ?)
insert into users_movies (user_id, movie_id) values (?, ?)
insert into users_roles (user_id, role_id) values (?, ?)
select user0_.id as id1_2_0_, movie2_.id as id1_0_1_, user0_.password as password2_2_0_, user0_.username as username3_2_0_, movie2_.category as category2_0_1_, movie2_.country as country3_0_1_, movie2_.description as descript4_0_1_, movie2_.release_date as release_5_0_1_, movie2_.title as title6_0_1_, movies1_.user_id as user_id1_3_0__, movies1_.movie_id as movie_id2_3_0__ from users user0_ left outer join users_movies movies1_ on user0_.id=movies1_.user_id left outer join movies movie2_ on movies1_.movie_id=movie2_.id where user0_.id=1
delete from users_movies where user_id=? and movie_id=?
delete from movies where id=?
0 голосов
/ 21 июня 2019

Проблема решена, вместо использования mappedBy я добавил аннотацию JoinTable также к сущности Movie, и теперь она работает как надо.

0 голосов
/ 21 июня 2019

это ожидаемое поведение при использовании CascadeType.ALL, которое неявно включает в себя CascadeType.REMOVE - удаляет все связанные сущности при удалении сущности-владельца.

Поскольку вы используете CascadeType.ALL с обеих сторонассоциации, в результате вы в конечном итоге удаляете записи больше, чем вы на самом деле намеревались.

Чтобы избежать этого:

  • Вам необходимо удалить CascadeType.ALL или изменить его начто-то подходящее, например MERGE / PERSIST
  • Самостоятельно обрабатывайте удаление сущностей.
  • Попробуйте использовать опцию пакетного удаления, указав идентификатор связанной сущности.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...