清除与 JPA / JPQL 的多对多关系

Posted

技术标签:

【中文标题】清除与 JPA / JPQL 的多对多关系【英文标题】:Clear ManyToMany Relationship with JPA / JPQL 【发布时间】:2020-11-26 01:55:39 【问题描述】:

我有用户和角色。每个用户可以有多个角色。

我想要进行批量操作,例如删除所有用户角色但保留用户和角色。 那么我怎样才能只截断 manyToMany 表呢?

很长的路要走 findAllUsers -> 对于每个 user.roles = new Hashset() -> saveAll(users)

@Entity
@Table
public class Role 

    @Id
    @Column(name = "id", unique = true, nullable = false)
    private Long id;

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

@Entity
@Table
public class User 

    @Id
    @Column(name = "id", unique = true, nullable = false)
    private Long id;

    @ManyToMany(cascade = CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST)
    @JoinTable(
            name = "UserRole",
            joinColumns = @JoinColumn(name = "id"),
            inverseJoinColumns = @JoinColumn(name = "id"))
    private Set<Role> roles = new HashSet<>();

@Repository
public interface UsersRepository extends JpaRepository<User, Long> 

    @Modifying
    @Query("UPDATE User u SET u.roles = null")
    void clearAllRoleRelations();

我已经尝试过了,但是得到了一个异常 不支持 DML 操作 [UPDATE users.entity.User u SET u.roles = null]

【问题讨论】:

你能展示你的实体吗? 更新方法应该返回一个 int 或 void。也尝试添加@Transactional 【参考方案1】:

放弃@ManyToMany 并为连接表创建一个实体。这样您就可以完全控制删除。

【讨论】:

【参考方案2】:

我让它工作了,但是使用本机查询,如果我想在同一个事务中使用它,则需要 entityManager.clear。

    @Modifying
    @Query(nativeQuery = true, value = "DELETE FROM user_role")
    void clearAllRoleRelations();

  @Autowired
  private EntityManager entityManager;
    

  @Test
    public void clearAllRoleRelations() 

        //given
        Role roleIn = new Role();
        roleIn.setId(27L);

        User userIn = new User();
        userIn.Id(12L);

        //do
        roleIn = rolesRepository.save(roleIn);
        userIn = usersRepository.save(userIn);
        userIn.getRoles().add(roleIn);
        usersRepository.save(userIn);

        //verify
        usersRepository.clearAllRoleRelations();

        //important within the same transaction (native query)
        entityManager.clear();

        Optional<User> userOut = usersRepository.findById(userIn.getId());
        assertThat(userOut.isPresent()).isTrue();
        assertThat(userOut.get()).isEqualTo(userIn);
        assertThat(userOut.get().getRoles()).isEmpty();
    

【讨论】:

以上是关于清除与 JPA / JPQL 的多对多关系的主要内容,如果未能解决你的问题,请参考以下文章

使用 JPA 映射与属性的多对多关系

多对多关系中没有项目的实体的 JPQL

与 Play Framework 1.2.5 JPA 的多对多关系

JPA 与存储在不同数据库中的用户实体的多对多关系

使用 JPA 和 Hibernate 提供程序的多对多关系不会创建主键

JPA:多对多关系 - JsonMappingException:无限递归