【问题标题】:Relation table delete-cascade in 4 cases but Entity-config allows only 2关系表删除级联在 4 种情况下,但 Entity-config 只允许 2
【发布时间】:2019-07-12 08:53:53
【问题描述】:

我有两张普通表和一张关系表。

 --------------------------------------------------
|  Group         | Membership      | User          |
| (ID, NAME)     |(GRP_ID, U_ID)   |(ID, FORENAME) |
 --------------------------------------------------
|  1,  Admin     | 1,      1       | 1, Joe        |
 --------------------------------------------------

会员有两个外键

FK1 Membership.GRP_ID -> Group.ID
FK2 Membership.U_ID   -> User.ID

我可以将cascade-delete 设置为每个外键(FK1FK2)。


事实 1

如果 FK1FK2 都没有删除级联,我既不能删除 Admin 也不能删除 Joe,因为他们仍处于“会员资格”状态。

CREATE TABLE Membership (
    GRP_ID INT NOT NULL,
    U_ID INT NOT NULL,
    FOREIGN KEY (GRP_ID) REFERENCES Group (id),
    FOREIGN KEY (U_ID) REFERENCES User (id)
);

事实 2

如果FK1 级联删除但FK2 没有级联删除,则可以删除管理员(删除成员资格)但不能删除乔。

CREATE TABLE Membership (
    GRP_ID INT NOT NULL,
    U_ID INT NOT NULL,
    FOREIGN KEY (GRP_ID) REFERENCES Group (id) ON DELETE CASCADE,
    FOREIGN KEY (U_ID) REFERENCES User (id) 
);

事实 3

如果FK2 级联删除但FK1 没有级联删除,您可以删除Joe(删除成员资格)但不能删除管理员。

CREATE TABLE Membership (
    GRP_ID INT NOT NULL,
    U_ID INT NOT NULL,
    FOREIGN KEY (GRP_ID) REFERENCES Group (id),
    FOREIGN KEY (U_ID) REFERENCES User (id) ON DELETE CASCADE
);

事实 4

如果FK2级联删除FK1级联​​删除。删除 Joe 将删除成员资格,但 Admin 保持不变。删除 Admin 将删除成员资格,但 Joe 保持不变。

CREATE TABLE Membership (
    GRP_ID INT NOT NULL,
    U_ID INT NOT NULL,
    FOREIGN KEY (GRP_ID) REFERENCES Group (id) ON DELETE CASCADE,
    FOREIGN KEY (U_ID) REFERENCES User (id) ON DELETE CASCADE
);


组的 Java 代码:

// @formatter:off
import javax.persistence.*;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.io.Serializable;
import javax.persistence.ManyToOne;
import javax.persistence.JoinColumn;
import javax.persistence.Column;
import javax.persistence.Version;
import javax.persistence.SequenceGenerator;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import org.hibernate.envers.Audited;
import java.util.LinkedHashSet;
import javax.persistence.OneToMany;
import java.util.Set;
import javax.persistence.OrderBy;
import javax.persistence.ManyToMany;
import javax.persistence.JoinTable;

@Entity
@Table(name="Group")
@SuppressWarnings("serial")
public class Group implements java.io.Serializable {
  private Integer id;
  private Set<User> users = new LinkedHashSet<>();
  private String name;

  @Id
  @Column(name = "ID", nullable = false)
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "gen241738")
  @SequenceGenerator(name = "gen241738", sequenceName = "seq_group_id")
  public Integer getId() {
    return id;
  }
  public void setId(Integer id) {
    this.id = id;
  }

  @OrderBy
  @ManyToMany
  @JoinTable(name="Membership", joinColumns = {
    @JoinColumn(name="GRP_ID", referencedColumnName="ID", nullable=false),
  }, inverseJoinColumns = {
    @JoinColumn(name="U_ID", referencedColumnName="ID", nullable=false)
  })
  public Set<User> getUsers() {
    return users;
  }
  public void setUsers(Set<User> users) {
    this.users = users;
  }

  @Column(name = "NAME", nullable = false)
  public String getName() {
    return this.name;
  }
  public void setName(String name) {
    this.name = name;
  }
}
//@formatter:on


问题

当关系表包含两个外键时,将可能性扩展到2x2=4 情况,为什么注释@ManyToMany 只允许一个删除级联?

【问题讨论】:

  • 你能用示例代码解释一下吗?使用了哪个级联?
  • @MostafaMashayekhi 当然,你喜欢什么语言和数据库?
  • 这很清楚,因为你使用了java和spring标签
  • @PeterRader 没关系,我试图提供帮助,但您的出色态度令人讨厌。体验与 Stackoverflow 的使用不成正比。祝你好运。
  • @Villat 你说得对,这是一种理想主义的态度,很抱歉偷了你的时间。我更改了问题以添加理想主义标签。

标签: java hibernate many-to-many cascading-deletes


【解决方案1】:

当关系表包含两个外键时 2x2=4 的可能性,为什么注释 @ManyToMany 只允许一个删除级联?

级联不仅由类型定义,还由relationship 的拥有方定义:

使用关系的实体通常依赖于 关系中存在其他实体。例如,一条线 item 是订单的一部分;如果订单被删除,订单项也会 应该删除。这称为级联删除关系。

对于@ManyToMany

每个多对多关联都有两个方面,拥有方和 非拥有方或反向方。连接表在 拥有方。如果关联是双向的,任何一方都可能是 指定为拥有方。如果关系是双向的, 非拥有方必须使用 ManyToMany 的 mappedBy 元素 注释以指定拥有的关系字段或属性 边。 关系的连接表(如果不是默认值)在拥有方指定。

所以从你的例子来看,Group 是拥有方,我认为User 是非拥有方,所以它代表 fact 2fact 3 反之亦然。

@Entity
@Table(name="Group")
@SuppressWarnings("serial")
public class Group implements java.io.Serializable {

  @OrderBy
  @ManyToMany
  @JoinTable(name="Membership", joinColumns = {
    @JoinColumn(name="GRP_ID", referencedColumnName="ID", nullable=false),
  }, inverseJoinColumns = {
    @JoinColumn(name="U_ID", referencedColumnName="ID", nullable=false)
  })
  public Set<User> getUsers() {
    return users;
  }
}

如果关联是双向的,则任何一方都可以被指定为拥有方。如果您这样做,您将获得事实 4

的代表

对于最后一个示例,您应该将 Mapping 表的 POJO 表示定义为每个关系的拥有方。

我向您展示了没有丢失的配置/字段,并且所有情况都可以通过指定拥有方来完成。您错误地期望@ManyToMany 的字段cascade 进行整个级联配置。


刚刚在评论中发现您确实要求解释级联:

答案并没有帮助我理解什么是问题 级联=空

使用cascade,您正在指定必须级联到关联目标的操作。级联是由hibernate执行的,它不是db级别的级联操作。通过上面定义的关系,我们告诉UserGroup 关联是否也应该在Group 执行(使用适当的类型)或不执行(using cascade=null)时保持/合并/删除/刷新/分离。

【讨论】:

  • 我只是用你的例子来演示你对关系的定义是如何表现的。
  • 再说一次,我不知道,你知道。我认为您确实以这种方式定义了级联,因为 CascadeType.REMOVE 也会删除 User 并且此行为不符合您在问题中定义的预期级联可能性。请问您为什么不赞成我的回答?
  • 我编辑了我的答案,希望我回答了你的问题。
  • 好的,让我们再看看你的问题。您在关系表中为级联删除指定了 4 种情况。我将这 4 个案例转移到 java/hibernate 案例中,向您展示没有缺少配置/字段,所有这些都可以通过指定拥有方来完成。您错误地期望@ManyToMany 的字段cascade 进行整个级联配置,并象征性地提供另一个答案。
  • 刚刚编辑了我的答案,因为我只是解释上下文。
【解决方案2】:

在这种情况下,您不想在删除组或用户时删除另一方。

@ManytoMany 是维护两方的关系。因此,如果它设计为允许两个删除级联,它将:

  1. 很难理解
  2. 导致一些你不想看到的情况

维护关系最好的方法是直接操作关系表。之后,您可以根据需要删除/添加组表或用户表。

注解@ManytoMany,在我看来,是为了引导我们操作关系表。 我不知道我是否回答了你的问题。如果有,请告诉我,谢谢。

【讨论】:

  • 很抱歉,我没有注意到我写错了字。我想写组和用户。操作符这个词其实就是操作。
  • (...)is designed to lead us operate the(...)其实是让我们操作 ?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-11
  • 2016-01-17
  • 2017-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多