【问题标题】:Referential integrity constraint violation: when deleting Entity in Hibernate (H2 in memory DBMS)违反参照完整性约束:在 Hibernate 中删除实体时(内存 DBMS 中的 H2)
【发布时间】:2019-10-25 12:16:33
【问题描述】:

我正在构建我的第一个 Spring Boot 应用程序。我使用 Hibernate 和 H2 内存 DBMS。

我正在尝试构建的是一个代表多个应用商店的 REST API。我有一个名为 App 的实体和另一个名为 Store 的实体。一个商店可以包含许多应用程序,每个应用程序可以包含在多个商店中。但是,应用程序不知道它们包含在哪些商店中。我希望能够相互独立地删除应用程序和商店。仅仅因为商店被删除并不意味着其中的应用程序也应该被删除,反之亦然。应用可以在没有商店的情况下存在,没有应用的商店也可以。

这是我的实体的代码,LpApp 是 App 的实现,LpTemplate 是 Store 的实现:

@Entity
public class LpApp {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(nullable = false, updatable = false)
    private Long id;

    @NotBlank(message = "An app needs a non-empty name")
    @Column(nullable = false, updatable = false, unique = true)
    private String appName;

    // ... constructors, getters, setters, no further annotations
}

@Entity
public class LpTemplate {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(nullable = false, updatable = false)
    private Long id;

    @ManyToMany(fetch=FetchType.EAGER)
    @JoinTable(name = "template_apps",
        inverseJoinColumns = { @JoinColumn(name = "app_id") },
        joinColumns = { @JoinColumn(name = "template_id") })
    private Set<LpApp> apps = new HashSet<>();

    // ... constructors, getters, setters, no further annotations

}

在我尝试从我的 DBMS 中删除应用程序或商店之前,此方法运行良好。此时我得到一个 org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException。

我得到的异常如下(为简洁起见,我修剪了调用堆栈):

org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint ["APP_ID: PUBLIC.TEMPLATE_APPS FOREIGN KEY(APP_ID) REFERENCES PUBLIC.LP_APP(ID) (3)"; SQL statement:
delete from lp_app where id=? [23503-199]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
...
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
...
Caused by: org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Referential integrity constraint violation: "APP_ID: PUBLIC.TEMPLATE_APPS FOREIGN KEY(APP_ID) REFERENCES PUBLIC.LP_APP(ID) (3)"; SQL statement:
delete from lp_app where id=? [23503-199]

我显然做错了什么,但我不知道去哪里找。我想我没有正确使用 @ManyToMany 注释,或者它可能是我的用例的错误注释。

非常感谢。

【问题讨论】:

  • 我尝试使用您创建的实体并使用 cascade ALL 我能够成功执行删除事务。为更清楚起见,请在您尝试删除的位置发布代码。
  • 我使用 org.springframework.data.repository.CrudRepository 中的 void deleteById(ID id)。

标签: java hibernate h2


【解决方案1】:

您需要添加级联属性来告诉hibernate不要在删除操作时删除实体。级联有不同的选项。请参阅this 链接以了解不同的选项。

【讨论】:

  • 但是我需要设置什么样的级联属性呢?我用 REMOVE 试过了,但我得到了同样的例外。我也尝试了所有,没有任何不同。
  • 如果您的需要只是在加载 App 或 Store 实体时从数据库中读取,那么您可以使用 NONE,因为它会忽略所有操作并且不会将更改同步到数据库
  • 我肯定需要在某个时间点删除应用程序和商店。当发生这种情况时,数据库中将应用程序映射到模板的 template_apps 表需要正确更新。我该如何做到这一点?
【解决方案2】:

答案的简短版本是您正在尝试删除与另一条记录具有现有关系的记录。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-19
    • 1970-01-01
    • 2019-07-25
    相关资源
    最近更新 更多