Java 在JPA中删除多对多关系时出现奇怪的sql行为
这是一个关于Hibernate生成的sql的问题,关于在多对多映射下删除一个关系,而不是“级联”问题 我使用JPA2和hibernate作为它的实现 我有两个模型,用户和角色。一个用户可以有多个角色,一个角色可以有多个用户,因此他们是多对多映射:Java 在JPA中删除多对多关系时出现奇怪的sql行为,java,hibernate,jpa-2.0,Java,Hibernate,Jpa 2.0,这是一个关于Hibernate生成的sql的问题,关于在多对多映射下删除一个关系,而不是“级联”问题 我使用JPA2和hibernate作为它的实现 我有两个模型,用户和角色。一个用户可以有多个角色,一个角色可以有多个用户,因此他们是多对多映射: @Entity class User{ @Id Long id; @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH) @JoinTable(na
@Entity
class User{
@Id Long id;
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
@JoinTable(name = "user_role", inverseJoinColumns = @JoinColumn(name = "role_id"),
joinColumns = @JoinColumn(name = "user_id"))
private List<Role> roles;
}
@Entity
class Role{
@Id Long id;
@ManyToMany(fetch = FetchType.LAZY,cascade = CascadeType.REFRESH, mappedBy = "roles")
private List<User> users;
}
现在问题来了,我想要的只是从一个用户中删除一个角色(不是删除一个用户或角色,一个用户和一个角色之间只有一个关系,意味着只需要从表user\u role
中删除一条记录)。以下是我尝试的代码:
public void removeOneRoleFromUser(long userId, long roleId){
User user = userService.getById(userId);
Role role = roleService.getById(roleId);
user.getRoles().remove(role); //here
userService.update(user);
}
当我执行这段代码时,该角色确实从用户中删除了。但是当我检查hibernate为其生成的sql时,它不是我所期望的,hibernate生成的sql是:
delete from user_role where user_id = {userId}
insert into user_role values({user_id}, {role_id_not_removed})
...
insert into user_role values({user_id}, {another_role_id_not_removed})
因此,要从一个用户中删除一个角色,请先从该用户中删除所有角色,然后将不应删除的角色逐个添加回该用户。
我所期望的只是一句sql语句:
delete from user_role where user_id = {userId} and role_id = {role_id}
我知道还有其他一些方法可以存档,比如引入另一个实体UserRoleMapping
,它映射到表user\u role
,然后直接删除一个UserRoleMapping实例将从一个用户中删除一个角色;但是我想知道,有没有什么解决方案可以用当前的解决方案达到预期效果。我没有检查过这是真的,但它有很多优点
没有任何索引列,列表实际上就是一个包:没有顺序,并且允许重复。因此Hibernate认为在用户的角色列表中可能有两次相同的角色
所以发出delete from user\u role where user\u id=?而role_id=?
是不可能的,因为它可能会删除多个角色,而不仅仅是从列表中删除的角色
尝试添加索引列,或者使用
集合
而不是列表
来处理当前映射,这就是方法。可能有一些特定于hibernate的“提示”/etc来更改此行为。但是请记住,“过早优化是万恶之源(tm)”,这只是一个示例,而不是我们应用程序中的真实场景。在我们的应用程序中,一个模型可能有很多其他模型,因此当删除一个关系时会产生很多sql语句(可能有数百个)。切换到“从列表中设置”对我来说很有用,但我宁愿使用列表。联接表的主键已经包括联接外键和反向联接外键,它们是表中仅有的两列,所以我不明白为什么这不起作用。还有别的事吗?
delete from user_role where user_id = {userId} and role_id = {role_id}