如何在JPA(和相应的连接表行)中删除具有ManyToMany关系的实体?
假设我有两个实体:组和用户。 每个用户可以是多个组的成员,每个组可以有多个用户。
@Entity public class User { @ManyToMany Set<Group> groups; //... } @Entity public class Group { @ManyToMany(mappedBy="groups") Set<User> users; //... }
现在我想删除一个组(假设它有很多成员)。
问题是当我在某个Group上调用EntityManager.remove()时,JPA提供者(在我的情况下是Hibernate) 不会从连接表中删除行,并且由于外键约束,删除操作失败。 在用户上调用remove()可以正常工作(我想这与拥有关系的一方有关)。
那么在这种情况下我该如何删除一个组?
我唯一能想到的方式是加载组中的所有用户,然后为每个用户从他的组中删除当前组并更新用户。 但是,对于我来说,只要能够删除这个组就可以调用组中的每个用户的update(),这似乎是荒谬的。
- 关系的所有权取决于您将“mappedBy”属性放置到注释的位置。 你把'mappedBy'的实体是不是所有者的实体。 双方都没有机会成为所有者。 如果您没有“删除用户”用例,则可以简单地将所有权转移到
Group
实体,因为当前User
是所有者。 - 另一方面,你一直没有问,但有一点值得了解。
groups
和users
不相互结合。 我的意思是,从Group1.users中删除User1实例后,User1.groups集合不会自动更改(这对我来说是相当令人惊讶的), - 总而言之,我build议你决定谁是主人。 假设
User
是所有者。 然后,删除用户时,关系用户组将自动更新。 但是,删除一个组时,你必须小心地删除这个关系,像这样:
entityManager.remove(group) for (User user : group.users) { user.groups.remove(group); } ... // then merge() and flush()
以下为我工作。 将以下方法添加到非关系所有者的实体(组)
@PreRemove private void removeGroupsFromUsers() { for (User u : users) { u.getGroups().remove(this); } }
请记住,为了这个工作,本集团必须有一个更新的用户列表(这不是自动完成的)。 因此,每次将用户组添加到用户实体中的组列表中时,还应该将用户添加到组实体中的用户列表中。
我find了一个可能的解决scheme,但是…我不知道这是一个很好的解决scheme。
@Entity public class Role extends Identifiable { @ManyToMany(cascade ={CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}) @JoinTable(name="Role_Permission", joinColumns=@JoinColumn(name="Role_id"), inverseJoinColumns=@JoinColumn(name="Permission_id") ) public List<Permission> getPermissions() { return permissions; } public void setPermissions(List<Permission> permissions) { this.permissions = permissions; } } @Entity public class Permission extends Identifiable { @ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}) @JoinTable(name="Role_Permission", joinColumns=@JoinColumn(name="Permission_id"), inverseJoinColumns=@JoinColumn(name="Role_id") ) public List<Role> getRoles() { return roles; } public void setRoles(List<Role> roles) { this.roles = roles; }
我试过这个,它的工作原理。 当你删除angular色时,关系也被删除(但不是权限实体),当你删除权限时,与angular色的关系也被删除(但不是angular色实例)。 但是,我们映射一个单向关系两次,两个实体都是关系的所有者。 这可能会导致一些问题hibernate? 哪种types的问题?
谢谢!
上面的代码是从另一个职位相关。
作为JPA / Hibernate解决scheme的替代scheme:可以在连接表的foregin键的数据库定义中使用CASCADE DELETE子句,如(Oracle语法):
CONSTRAINT fk_to_group FOREIGN KEY (group_id) REFERENCES group (id) ON DELETE CASCADE
这样,DBMS自己在删除组时自动删除指向该组的行。 无论是从Hibernate / JPA,JDBC,数据库手动删除还是其他任何方式删除它都可以。
所有主要的DBMS(Oracle,MySQL,SQL Server,PostgreSQL)都支持级联删除function。
对于它的价值,我正在使用EclipseLink 2.3.2.v20111125-r10461,如果我有一个@ManyToMany单向关系,我会观察你描述的问题。 但是,如果我将其更改为双向@ManyToMany关系,则可以从非拥有方删除实体,并且适当地更新JOIN表。 这一切都没有使用任何级联属性。
这是一个很好的解决scheme。 最好的部分是在SQL方面 – 微调到任何级别都很容易。
我使用MySql和MySql Workbench来级联删除所需的外键。
ALTER TABLE schema.joined_table ADD CONSTRAINT UniqueKey FOREIGN KEY (key2) REFERENCES schema.table1 (id) ON DELETE CASCADE;