【问题标题】:How to cascade @OneToOne removal?如何级联@OneToOne 删除?
【发布时间】:2015-09-14 10:06:56
【问题描述】:

我想创建一个@OneToOne 映射,其中根实体通过外键约束引用子实体。

@Entity
public class MainEntity {
    @Id private long id;

    @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "fk_sheet_id", foreignKey = @ForeignKey(name = "fk_sheet"))
    private SheetEntity sheet;
}

@Entity
public class Sheet {
    @Id private long id;
    //...

    @OneToOne(mappedBy = "sheet")
    private GiataHotelEntity mainEntity;
}

问题:当我转到数据库并在MainEntity 上选择truncate cascade 时,关联的@OneToOne Sheet没有删除。

如果我反转映射并使Sheet 成为拥有方,那么这个级联删除将起作用!但我希望 MainEntity 成为拥有方。

我在这里可能做错了什么?

【问题讨论】:

  • 您的数据库中是否存在从 Sheet 到 MainEntity 的外键?
  • 是的,“mainEntity”有一个fk_sheet_id 列,其键为Sheet 实体。但是当我删除 MainEntity 时,工作表数据仍然存在。
  • 但是Sheet没有fk_mainentity_id?
  • 不,工作表没有外键!
  • 在您投票的答案下阅读我的评论。此外,您可能会在我的回答中发现一些有用的信息。

标签: java database hibernate postgresql


【解决方案1】:

当您运行 truncate MainEntity 级联时,它应该截断 MainEntity 表和任何使用 MainEntity 作为外键的表,这不是这里的情况。在你的情况下 - 外键是MainEntity(列fk_sheet_id)。如果通过在Sheet 表中使用外键(指MainEntity 中的主键)来创建关系,那么您的截断脚本将起作用。

【讨论】:

  • 如果我从不单独获取工作表,而是始终与主要实体一起获取 - 哪个实体必须是拥有方?将 fk_mainentity_id 设置为工作表会更好吗?
  • @membersound 为了满足您的要求,我将在 Sheet 表中声明外键并将其设置为 NOT NULL。 hibernate 怎么样,你可以在任何一方声明所有权,但如果你使用@ForeignKey,它应该高于数据库中的真实外键。
【解决方案2】:

CASCADE 自动截断所有具有外键的表 对任何命名表的引用,或对添加到 由于 CASCADE 的分组。

http://www.postgresql.org/docs/9.4/static/sql-truncate.html

看到像fk_sheet_id 这样的命名,我想在 MainEntity 中有外键到数据库中的 Sheet,但反之则不然。 因此,Sheet 不受 MainEntity 上的截断影响是正确的,因为 Sheet 没有 MainEntity 的外键。您可能需要在工作表上申请truncate cascade 吗?

在第二种情况下,当您更改所有者时,似乎 hibernate 在 Sheet 表中为您生成了一个外键。

当 ConstraintMode 值为 CONSTRAINT,但 未指定 foreignKeyDefinition 元素,提供者将 生成外键约束,其更新和删除操作它 确定最适合的连接列 应用了外键注释。

http://docs.oracle.com/javaee/7/api/javax/persistence/ForeignKey.html

【讨论】:

    【解决方案3】:

    如果 MainEntity 是关系的所有者,则意味着它依赖于 Sheet。如果 MainEntity 上的删除(在 Hibernate 之外运行)传播并删除关联的工作表很重要,则应将工作表声明为关系的所有者。

    此外,JPA 没有指定如何以及是否应将级联委托给 DDL。

    如果在数据库级别定义此级联对您很重要,您可以使用 特定于 Hibernate 的注释:@OnDelete

    @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "fk_sheet_id", foreignKey = @ForeignKey(name = "fk_sheet"))
    @OnDelete(action = OnDeleteAction.CASCADE)
    private MainEntity mainEntity;
    

    【讨论】:

      猜你喜欢
      • 2016-12-13
      • 2011-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多