如何避免使用 JPA 在实体关系中违反外键约束
Posted
技术标签:
【中文标题】如何避免使用 JPA 在实体关系中违反外键约束【英文标题】:How to avoid foreign key constraint violationin in entity relationships using JPA 【发布时间】:2021-02-25 15:54:07 【问题描述】:@Entity
@Table(name = "PERSISTENCE_USER")
public class User implements Serializable
// HERE IS A SNIPPET
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@NotNull
private String firstName;
@NotNull
private String lastName;
................
@Entity
@Table(name = "PERSISTENCE_ORDER")
@NamedQueries(
@NamedQuery(
name = "findAllorders",
query = "SELECT o FROM CustomerOrder o"
),
@NamedQuery(
name = "deleteAll",
query = "DELETE FROM CustomerOrder"
)
)
public class CustomerOrder implements Serializable
//HERE IS A SNIPPET
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@NotNull
String status;
@NotNull
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
private List<LineItem> lineItems;
@NotNull
@ManyToOne
private User customer;
...........
当我尝试删除具有单向 @ManyToOne 与 User 实体的 CustomerOrder 实体时,我收到以下错误:
Internal Exception: org.apache.derby.shared.common.error.DerbySQLIntegrityConstraintViolationException: DELETE on table 'PERSISTENCE_ORDER' caused a violation of foreign key constraint 'PRSSTNCSRPRs-s-rDRSD' for key (21). The statement has been rolled back.
Error Code: 20000
Call: DELETE FROM PERSISTENCE_ORDER
Query: DeleteAllQuery(name="deleteAll" referenceClass=CustomerOrder sql="DELETE FROM PERSISTENCE_ORDER")
at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:331)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:905)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeNoSelect(DatabaseAccessor.java:967)
............................................................................
............................................................................
Caused by: org.apache.derby.shared.common.error.DerbySQLIntegrityConstraintViolationException: DELETE on table 'PERSISTENCE_ORDER' caused a violation of foreign key constraint 'PRSSTNCSRPRs-s-rDRSD' for key (21). The statement has been rolled back.
之后,我尝试在删除 CustomerOrder 实体之前先删除 User 实体,但这没有任何区别。我应该如何定义实体关系映射以避免此错误?
谢谢
PS:我正在使用 Glassfish 5.1,EclipseLink 在 Windows 10 64 位和 Apache Derby DB 上运行【问题讨论】:
您没有在此处使用 JPA entityManager.remove 逻辑删除单个实体实例,您似乎正在发出“DELETE FROM CustomerOrder”批量删除查询。 JPA 不会为您做任何事情——它完全按照 JPQL 的要求发出 SQL——因此在删除它们之前,您可以通过清空或删除对要删除的行的任何引用来维护它们。我们不知道还有什么可能引用您的 CustomerOrder,但您似乎有一个 LineItems 列表,这些 LineItems 可能映射到需要清理其行的表。 谢谢克里斯。你是对的。自从我上周撰写这篇文章以来,我已经更改了我的实体映射,如这篇文章***.com/questions/66425106/… 所示,但现在我正在努力解决一个不同的问题。如果您对答案发表评论,我会检查它是否被接受。 【参考方案1】:当发出“DELETE FROM CustomerOrder”批量删除查询时,JPA 不会为您做任何事情 - 它完全按照 JPQL 的要求发出 SQL - 因此您可以通过清空或删除任何引用来维护到要删除的行,然后再删除它们。
异常本身表明违反了 FK 约束“PRSSTNCSRPRs-s-rDRSD”,可以在数据库中找到它,以准确告诉您是哪个关系导致了问题。查看 CustomerOrder 实体,lineItems 集合的映射方式是将外键放入 LineItems 表中,这需要在删除成功之前清理这些行。
【讨论】:
以上是关于如何避免使用 JPA 在实体关系中违反外键约束的主要内容,如果未能解决你的问题,请参考以下文章
如何解决无法添加或更新子行:Spring JPA 中的外键约束失败错误?
错误:删除表违反外键约束。密钥 id 仍然从表中引用(很多)