【问题标题】:JPA cant delete @OneToOne if @JoinTable is defined如果定义了 @JoinTable,JPA 无法删除 @OneToOne
【发布时间】:2019-06-05 14:32:15
【问题描述】:

我有一个有趣的“问题”,即现象。

快速信息:

  • _BaseEntity 是一个 @MappedSuperclass,它可以处理 ID、hashCode、equals、compareTo 等,并且在我的所有项目中都可以正常工作)
  • 我在 MySQL DB 上使用 Payara (EclipseLink)
  • @Expose 是一个 GSON 标签
  • 我发现了很多类似的主题,但没有一个回答我的问题,或者区分有/没有@JoinTable,或者以解决的方式得到答案......
  • 关系是单方面的,即仅来自Thema->TopThema,并且明确地没有TopThema->Thema

工作示例 当我有这样的实体设置时

@Entity
@Table(name = Thema.TABLE_NAME)
public class Thema extends _BaseEntity {
    static public final String TABLE_NAME = UEntity.TABLE_PREFIX + "Thema";

    @Expose @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true) 
    private TopThema topThema;
}

我可以简单地EntityManager.remove()它。

.

示例不起作用

但是如果是这样定义的

@Entity
@Table(name = Thema.TABLE_NAME)
public class Thema extends _BaseEntity {
    static public final String TABLE_NAME = UEntity.TABLE_PREFIX + "Thema";

    @Expose @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true) 
    @JoinTable(name = TABLE_NAME + "_topThema")
    private TopThema topThema;
}

(有一个中间表“GP_Thema_topThema”,由@JoinTable(name = TABLE_NAME + "_topThema") 定义,然后EntityManager.remove() 抛出异常:

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: 无法删除或更新父行:外键约束失败 (test_PT_local.GP_Thema_topThema, 约束 FK_GP_Thema_topThema_topThema_ID 外键 (topThema_ID) 参考GP_TopThema (ID))

我知道使用额外的@JoinTable 没有多大意义,因为引用也可以作为“GP_Thema”保存在“GP_Thema”中。“TOPTHEMA_ID”。 另外:这两个实体定义在 Java 端同样适用。

但出于兴趣:即使我设置了cascade = CascadeType.ALLorphanRemoval = true,为什么JPA 无法删除@JoinTable GP_Thema_topThema 中的条目?

更新:因为@JoinTable我也不能 - 先删除 TopThema,然后是 Thema(在 TopThema 删除时抛出 MySQLIntegrityConstraintViolationException) - det Thema.topThema = null,然后更新(再次抛出MySQLIntegrityConstraintViolationException

【问题讨论】:

  • 您是否在TopThema 中定义了关联的反面?如果是这样,请同时发布该实体
  • 不,这只是一方面。谢谢你的提示;-)
  • 它能解决你的问题吗?
  • 什么解决了这个问题?
  • 你试过@JoinTable( name = TABLE_NAME + "_topThema"", joinColumns = @JoinColumn(name = "topThema_ID"), inverseJoinColumns = @JoinColumn(name = "GP_TopThema") )吗?

标签: jpa jakarta-ee one-to-one jointable


【解决方案1】:

不是 JPA 不能删除实体,而是实际的数据库。您正在寻找的是一个可延迟的约束,这在 MySQL 中是不可能的。

关于可延迟约束的 Mysql 文档here

与一般的 MySQL 一样,在插入、删除或更新许多行的 SQL 语句中,InnoDB 逐行检查 UNIQUE 和 FOREIGN KEY 约束。在执行外键检查时,InnoDB 在它必须查看的子记录或父记录上设置共享行级锁。 InnoDB 立即检查外键约束;检查不推迟到事务提交。根据 SQL 标准,默认行为应该是延迟检查。也就是说,仅在处理完整个 SQL 语句后才检查约束。在 InnoDB 实现延迟约束检查之前,有些事情是不可能的,例如删除使用外键引用自身的记录

您是否考虑过切换到PostgreSQL

在事务提交之前不会检查 DEFERRED 约束

【讨论】:

  • 很棒的答案!非常感谢!在赏金时间用完之前,没有时间在 Postgres 上测试问题,但这看起来是一个有效的答案。将与 PG 和 Oracle 核实。
【解决方案2】:

作为旁注,您可以使用 JPA 和 MySQL 删除您的 Thema 实体...为此,您只需将您的 @JoinTable (GP_Thema_topThema) 的外键声明为“ON DELETE CASCADE”... .

例子:

CREATE TABLE GP_Thema_topThema(
    thema_ID integer NOT NULL,
    topThema_ID integer NOT NULL,
    FOREIGN KEY (thema_ID)
        REFERENCES thema (id)
        ON DELETE CASCADE,
    FOREIGN KEY (topThema_ID)
        REFERENCES top_thema(id)
        ON DELETE CASCADE
)

这样如果数据库收到删除Thema实体的命令,那么任何相关的GP_Thema_topThema实体(或元组)也将被删除...

【讨论】:

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