JPA:如何删除单向多对多关系中的链接记录?

时间:2013-12-17 06:17:09

标签: hibernate jpa

对于实体“活动”和“发票”,我有多对多的单向映射。映射仅在Activity实体中设置(我不需要来自Invoice端的访问活动)。

@ManyToMany
@JoinTable(name = "OP_ACTIVITY_INVOICE_XREF", joinColumns = @JoinColumn(name = "ACTIVITY_ID", referencedColumnName = "OBJECT_ID"), inverseJoinColumns = @JoinColumn(name = "INVOICE_ID", referencedColumnName = "OBJECT_ID"))
private Set<Invoice> invoices;

插入和更新工作正常,但我在删除活动时遇到问题。删除活动代码如下:

    activity.getInvoices().clear();
    em.remove(activity);

当我运行这些代码时,我认为em将首先从连接表中删除记录,然后删除活动记录(发票记录应保持不变)。但是连接表中的记录永远不会被删除。我收到这个外键错误:

[STDOUT] Hibernate: delete from OP_ACTIVITY where OBJECT_ID=?
[JDBCExceptionReporter] SQL Error: 1451, SQLState: 23000 
ERROR [JDBCExceptionReporter] Cannot delete or update a parent row: a foreign key constraint fails (`prod/op_activity_invoice_xref`.......

我在这里做错了什么?请帮助,谢谢。

1 个答案:

答案 0 :(得分:1)

我认为你需要@ManyToMany(cascade = {CascadeType.REMOVE})选项。

  

CascadeType.REMOVE:删除实体时,也删除实体   在这个领域举行。

活动:

@ManyToMany(cascade = {CascadeType.REMOVE})
@JoinTable(name = "OP_ACTIVITY_INVOICE_XREF", joinColumns = @JoinColumn(name = "ACTIVITY_ID",  referencedColumnName = "OBJECT_ID"), inverseJoinColumns = @JoinColumn(name = "INVOICE_ID", referencedColumnName = "OBJECT_ID"))
private Set<Invoice> invoices;

显然REMOVE不应与@ManyToMany一起使用(来自JPA 2.0规范):

  

关系建模注释约束了使用   cascade = REMOVE规范。级联= REMOVE规范应该   仅适用于指定为OneToOne或的协会   一对多。将cascade = REMOVE应用于其他应用程序的应用程序   协会不可携带。

您可以在Hibernate中尝试供应商扩展@OnDelete:

  

@OnDelete(动作= OnDeleteAction.CASCADE)

或者你可以手动完成:

for (Invoice invoice : activity.getInvoices()) {
   em.remove(invoice);
}
activity.getInvoices().clear();
em.remove(activity);
... flush() etc...

或者你可以注释@PreRemove: 将以下方法添加到不是关系所有者的实体(发票)

@PreRemove
private void removeInvoicesFromActivities() {
    for (Activity a : activities) {
        a.getInvoices().remove(this);
    }
}