【问题标题】:strange sql behavior when do deleting relation for many-to-many in JPA在JPA中删除多对多关系时出现奇怪的sql行为
【发布时间】:2012-05-18 16:27:53
【问题描述】:

这是关于Hibernate生成的sql关于在多对多映射下删除一个关系的问题,不是'级联'问题。

我使用 JPA 2 和 hibernate 作为它的实现。

我有两个模型,用户和角色。一个用户可以有多个角色,一个角色可以有多个用户,所以是多对多映射:

@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; 
 }

映射效果很好,休眠自动为这个映射创建三个表

table user
table role
table user_role

现在问题来了,我想要的只是从一个用户中删除一个角色(不是删除一个用户或一个角色,只是一个用户和一个角色之间的一种关系,意味着只需要从表中删除一条记录@987654323 @)。这是我尝试过的代码:

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}) 

所以要从一个用户中删除一个角色,hibernate首先从用户中删除所有角色,然后将那些不应该删除的角色一一添加回用户。

而我所期望的只是一个 sql 语句归档它:

delete from user_role where user_id = {userId} and role_id = {role_id}

我知道还有其他一些方法可以存档,比如引入另一个实体UserRoleMapping,它映射到表user_role,然后直接删除一个 UserRoleMapping 实例将从一个用户中删除一个角色;但我想知道是否有任何解决方案可以让我得到当前解决方案的期望。

【问题讨论】:

  • 使用您当前的映射,就是这样。可能有一些特定于休眠的“提示”/等来改变这种行为。但是请记住“过早的优化是万恶之源(tm)”
  • 这只是示例,并不是我们应用程序中的真实场景。在我们的应用程序中,一个模型可能有很多其他模型,因此删除一个关系时会产生很多 sql 语句(可能是数百个)。

标签: java hibernate jpa-2.0


【解决方案1】:

我没有检查过this explanation 是否属实,但它有优点。

没有任何索引列,List 实际上是一个包:没有顺序,允许重复。所以 Hibernate 认为你有可能在一个用户的角色列表中有两次相同的角色。

因此发布delete from user_role where user_id = ? and role_id = ? 是不可能的,因为它可能会删除多个角色,而不仅仅是您从列表中删除的角色。

尝试添加索引列,或使用Set&lt;Role&gt; 而不是List&lt;Role&gt;

【讨论】:

  • 从列表切换到设置对我有用,但我宁愿使用列表。连接表的主键已经包括连接和反向连接外键,这是表中仅有的两列,所以我不明白为什么这不起作用。还有别的吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-09
  • 1970-01-01
  • 2013-11-21
相关资源
最近更新 更多