JPA Hibernate 多对多级联

Posted

技术标签:

【中文标题】JPA Hibernate 多对多级联【英文标题】:JPA Hibernate many-to-many cascading 【发布时间】:2011-06-23 12:49:52 【问题描述】:

我正在使用 JPA 2.0 和休眠。我有一个 User 类和一个 Group 类,如下所示:

public class User implements Serializable 
    @Id
    @Column(name="USER_ID")
    private String userId;

    @ManyToMany
    @JoinTable(name = "USER_GROUP",
               joinColumns = 
                   @JoinColumn(name = "GROUP_ID")
               ,
               inverseJoinColumns = 
                   @JoinColumn(name = "USER_ID")
               
    )
    private Set<Group> groupList;

    //get set methods


public class Group

    @Id
    @Column(name="GROUP_ID")
    private String groupId;

    @ManyToMany(mappedBy="groupList")
    private Set<User> memberList;
    //get set methods

然后,我创建用户和组,然后将用户分配给组。

我想要的是当我删除组时,该组将被删除(当然)并且该组具有的所有用户组关系将从 USER_GROUP 连接表中自动删除,但用户本身不是从 USER 表中删除。

使用我上面的代码,当我删除一个组时,只会删除 GROUP 表中的行,并且用户在 USER_GROUP 连接表中仍然有一个已删除组的条目。

如果我像这样将级联放在 User 类中:

@ManyToMany(cascade=CascadeType.ALL)
@JoinTable(name = "USER_GROUP",
joinColumns =

    @JoinColumn(name = "GROUP_ID")
,
inverseJoinColumns =

    @JoinColumn(name = "USER_ID")
)
private Set<Group> groupList;

当我删除组时,用户也会被删除!

有什么方法可以实现我想要的吗?

【问题讨论】:

【参考方案1】:

按照您的映射方式,User 是关系的管理方,因此它将负责更新连接表。

JoinTable 映射从User 更改为Group,并使UsergroupList 属性具有mappedBy 属性。这会将组更改为关系的管理方,并对组进行持久/更新调用来管理连接表。

但请注意,您不能简单地将组添加到用户、保存用户并继续,而是必须将用户添加到组并保存组才能看到变化,但希望您无论如何都能密切管理这种关系。

【讨论】:

嗯,如果我按照你说的去做(我假设根本没有级联,因为你什么都没提到),当我有一个用户分配到某个组时,当我删除用户时会发生什么?连接表中的用户组关系会被删除吗?组本身会被删除吗? 如果你按照我说的那样做,用户组关系将完全由 Group 方面来管理。这意味着在您将用户从所有组中删除之前,您可能根本无法删除该用户。为了坚持下去,您必须从组中删除用户,然后保存组。仅删除用户不会删除用户组关系,也不会删除连接表。如果没有级联,删除组将删除关联,但不会删除用户,这就是您在原始问题中所说的。 我明白了...所以我必须使用该组作为管理方...有没有办法让双方都成为管理组?换句话说,当我删除用户时,用户和用户组也将被删除,但不会删除组,当我删除组时,组和用户组将被删除,但不会删除用户。 接上一条评论。还是只有硬的办法,即如果组是管理方,要删除一个用户,我必须先用组对象删除用户,保存组对象,最后删除用户?跨度> 只有一方可以作为任何双向关系的管理方。我尽可能避免双向关系,因为维持它们可能会很痛苦。您最好的选择是将其映射到满足您最常见用例的一侧,然后将操作包装在一个服务方法中,该方法将确保一切都发生,例如更新关系的非管理侧等.【参考方案2】:

如前所述,如果您不需要从用户端级联,则将关系设为组所有者。

然后,在删除组时尝试使用cascade=CascadeType.MERGE不删除级联用户。

【讨论】:

【参考方案3】:

换个角度看问题:

您可以将 FK 约束添加到您的多对多映射表。实际上,出于数据完整性的原因,您的数据库中应该始终有 FK。例如,在这种情况下,至少不能删除用户,同时在映射表中静默地留下孤立行。

当您有 FK 时,您可以在约束上指定 delete cascade referential action,数据库将管理映射表的自动删除,而不是实体的自动删除,就像您要求的那样。

【讨论】:

【参考方案4】:

你可以这样做

@PreRemove
private void removeMembers() 
    this.memberList.clear();

【讨论】:

以上是关于JPA Hibernate 多对多级联的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate/JPA 多对一与单对多

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

Hibernate多对多级联操作

Hibernate 多对多级联删除

JPA多对多删除实体

使用 @IdClass 的 JPA 多对多与额外列在 springTestContextPreparation Hibernate AnnotationException“没有持久的 id 属性”中失