Spring ManyToMany关系删除所有实体

Spring ManyToMany关系删除所有实体,spring,hibernate,jpa,Spring,Hibernate,Jpa,我有两个实体,用户和电影。他们有很多双向关系。我的问题是,当我通过控制器删除一部电影时,它也会删除所有与该电影相关的实体。我的用户和此用户角色以及电影实体。我要做的是,在删除时从表中除去刚刚离开的电影实体,并保留用户的角色,而不是全部删除 @Data @ToString @EqualsAndHashCode @Entity @Table(name = "movies") public class Movie { @Id @GeneratedValue(strategy = Ge

我有两个实体,用户和电影。他们有很多双向关系。我的问题是,当我通过控制器删除一部电影时,它也会删除所有与该电影相关的实体。我的用户和此用户角色以及电影实体。我要做的是,在删除时从表中除去刚刚离开的电影实体,并保留用户的角色,而不是全部删除

@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<>();
@数据
@托斯特林
@EqualsAndHashCode
@实体
@表(name=“movies”)
公映{
@身份证
@GeneratedValue(策略=GenerationType.IDENTITY)
私人长id;
@列(name=“title”)
私有字符串标题;
@列(name=“description”)
私有字符串描述;
@列(name=“发布日期”)
@时态(TemporalType.DATE)
私人日期发布日期;
@列(name=“country”)
私人国家;
@列(name=“category”)
私有字符串类别;
@许多(mappedBy=“电影”)
@ToString.Exclude
@EqualsAndHashCode.Exclude
private Set users=new HashSet();

@资料
@托斯特林
@实体
@表(name=“users”)
公共类用户{
@身份证
@GeneratedValue(策略=GenerationType.IDENTITY)
私人长id;
@列(name=“username”)
私有字符串用户名;
@列(name=“password”)
私有字符串密码;
@短暂的
私有字符串确认密码;
@多个(级联=级联类型.ALL)
@JoinTable(name=“users\u roles”,joinColumns={@JoinColumn(name=“user\u id”,referencedColumnName=“id”),
inverseJoinColumns={@JoinColumn(name=“role\u id”,referencedColumnName=“id”)}
@ToString.Exclude
@EqualsAndHashCode.Exclude
私有集角色=新HashSet();
@多个(级联=级联类型.ALL)
@JoinTable(name=“users\u movies”,joinColumns={@JoinColumn(name=“user\u id”,referencedColumnName=“id”)},
inverseJoinColumns={@JoinColumn(name=“movie\u id”,referencedColumnName=“id”)}
@ToString.Exclude
@EqualsAndHashCode.Exclude
private Set movies=new HashSet();

这是使用
CascadeType.ALL
时的预期行为,它隐式地包括
CascadeType.REMOVE
——在删除所属实体时删除所有相关实体

由于您使用的是关联两侧的
CascadeType.ALL
,因此您最终删除的记录超出了实际需要

为了避免这种情况:

  • 您需要删除
    CascadeType.ALL
    或将其更改为类似
    MERGE/PERSIST
  • 自行处理实体的删除
  • 考虑使用批删除选项指定关联的实体id

好吧,我不得不猜测您的
角色是什么样的,所以请包含完整的示例。您没有指定是使用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<>();

}
这将创建日志

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=?

问题解决了,我没有使用mappedBy,而是在电影实体中添加了一个JoinTable注释,现在它可以正常工作了。

对我来说很好。@K.Nicholas它不会删除相关实体?我的意思是,当我添加电影并试图删除它时,它也会删除用户和他的角色。因此,基本上它会删除所有内容,而不是删除just movie。对,可以使用JPA代码。奇怪的是,我在使用存储库添加电影时也遇到了一个问题,它没有将电影添加到联接表中。我不确定那里出了什么问题……我想得到的是将用户和电影添加到联接表中,而在删除电影时,只需从没有用户的表中删除电影。你能解释一下吗请给我一个例子,你是如何测试它的,以及它是如何为你工作的?如果不是,我会尝试处理这个问题,但如果你能给我一个例子,说明你是如何测试它的,我会更容易理解它。
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=?