如何级联删除属于 JPA 实体一部分的集合?

发布于 2024-12-08 22:21:43 字数 580 浏览 0 评论 0原文

@Entity
public class Report extends Model {

    public Date date;
    public double availability;

    @ElementCollection
    @Cascade(value={CascadeType.ALL})
    public Map<FaultCategory, Integer> categories;      
}

在我的一项工作中,我有以下代码:

int n = MonthlyReport.delete("date = ?", date);

这总是无法删除实体,并出现以下错误:

DELETE 语句与 REFERENCE 约束“FK966F0D9A66DB1E54”冲突。冲突发生在数据库“TFADB”、表“dbo.MonthlyReport_categories”、列“MonthlyReport_id”中。

如何指定映射,以便在删除报表时删除 categories 集合中的元素?

@Entity
public class Report extends Model {

    public Date date;
    public double availability;

    @ElementCollection
    @Cascade(value={CascadeType.ALL})
    public Map<FaultCategory, Integer> categories;      
}

In one of my jobs I have the following code:

int n = MonthlyReport.delete("date = ?", date);

This always fails to delete the entity with the following error:

The DELETE statement conflicted with the REFERENCE constraint "FK966F0D9A66DB1E54". The conflict occurred in database "TFADB", table "dbo.MonthlyReport_categories", column 'MonthlyReport_id'.

How can I specify the mapping so the elements from the categories collection get deleted when the report is deleted?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

本宫微胖 2024-12-15 22:21:43

仅当通过 EntityManager 完成操作时,级联删除(以及一般的级联操作)才有效。当通过 JP QL /HQL 查询以批量删除方式完成删除时则不会。当通过查询完成删除时,您无法指定将删除链接到 ElementCollection 中的元素的映射。

ElementCollection 注解没有cascade属性,因为操作总是级联的。当您通过 EntityManager.remove() 删除实体时,操作会级联到 ElementCollection。

您必须获取要删除的所有 MonthlyReport 实体,并为每个实体调用 EntityManager.remove。看起来除了在 Play 框架中使用此方法之外,您还可以在实体中调用删除方法。

Cascading delete (and cascading operations in general) is effective only when operation is done via EntityManager. Not when delete is done as bulk delete via JP QL /HQL query. You cannot specify mapping that would chain removal to the elements in ElementCollection when removal is done via query.

ElementCollection annotation does not have cascade attribute, because operations are always cascaded. When you remove your entity via EntityManager.remove(), operation is cascaded to the ElementCollection.

You have to fetch all MonthlyReport entities you want to delete and call EntityManager.remove for each of them. Looks like instead of this in Play framework you can also call delete-method in entity.

仲春光 2024-12-15 22:21:43

JT 提供的答案是正确的,但正如他/她的评论中指出的那样,对于我和 sebge2 来说并不完整。
@ElementCollection@OnDelete 的组合还需要 @JoinColumn()

后续示例:

@Entity
public class Report extends Model {
    @Id
    @Column(name = "report_id", columnDefinition = "BINARY(16)")
    public UUID id; // Added for the sake of this entity having a primary key
    public Date date;
    public double availability;

    @ElementCollection
    @CollectionTable(name = "report_category", joinColumns = @JoinColumn(name = "report_id")) // choose the name of the DB table storing the Map<>
    @MapKeyColumn(name = "fault_category_key") // choose the name of the DB column used to store the Map<> key
    @Column(name = "fault_category_value")     // choose the name of the DB column used to store the Map<> value
    @JoinColumn(name = "report_id")            // name of the @Id column of this entity
    @OnDelete(action = OnDeleteAction.CASCADE)
    @Cascade(value={CascadeType.ALL})
    public Map<FaultCategory, Integer> categories;      
}

此设置将创建一个名为 report 的表和另一个包含三列的 report_category 表:report_id、fault_category_key、fault_category_valuereport_category.report_idreport.report_id 之间的外键约束将为 ON DELETE CASCADE。我使用 Map测试了此设置。

The answer provided by J.T. is correct, but was incomplete for me and for sebge2 as pointed out in his/her comment.
The combination of @ElementCollection and @OnDelete further requires @JoinColumn().

Follow-up example:

@Entity
public class Report extends Model {
    @Id
    @Column(name = "report_id", columnDefinition = "BINARY(16)")
    public UUID id; // Added for the sake of this entity having a primary key
    public Date date;
    public double availability;

    @ElementCollection
    @CollectionTable(name = "report_category", joinColumns = @JoinColumn(name = "report_id")) // choose the name of the DB table storing the Map<>
    @MapKeyColumn(name = "fault_category_key") // choose the name of the DB column used to store the Map<> key
    @Column(name = "fault_category_value")     // choose the name of the DB column used to store the Map<> value
    @JoinColumn(name = "report_id")            // name of the @Id column of this entity
    @OnDelete(action = OnDeleteAction.CASCADE)
    @Cascade(value={CascadeType.ALL})
    public Map<FaultCategory, Integer> categories;      
}

This setup will create a table called report and another table report_category with three columns: report_id, fault_category_key, fault_category_value. The foreign key constraint between report_category.report_id and report.report_id will be ON DELETE CASCADE. I tested this setup with Map<String, String>.

前事休说 2024-12-15 22:21:43

我们找到了神奇的门票!将 OnDelete(action= OnDeleteAction.CASCADE) 添加到 ElementCollection。这允许我们从 SQL 中删除该项目(在实体管理器之外)。

We found the magic ticket! Add OnDelete(action= OnDeleteAction.CASCADE) to the ElementCollection. This allows us to remove the item from SQL (outside of the entityManager).

孤蝉 2024-12-15 22:21:43

作为 hibernate 特定注释 @org.hibernate.annotations.OnDelete 的替代方案,您还可以通过 @javax.persistence.ForeignKey 提供约束来自定义自动模式生成:

@CollectionTable(name = "foo_bar", foreignKey = @ForeignKey(
        name = "fk_foo_bar", 
        foreignKeyDefinition = "foreign key (foo_id) references Foo (id) on delete cascade"))
private List<String> bar;

As an alternative to the hibernate-specific annotation @org.hibernate.annotations.OnDelete, you can also provide the constraint via @javax.persistence.ForeignKey to customize automatic schema generation:

@CollectionTable(name = "foo_bar", foreignKey = @ForeignKey(
        name = "fk_foo_bar", 
        foreignKeyDefinition = "foreign key (foo_id) references Foo (id) on delete cascade"))
private List<String> bar;
简单气质女生网名 2024-12-15 22:21:43

我遇到了同样的问题,这是我的代码示例。

@ElementCollection
@CollectionTable(name = "table_tag", joinColumns=@JoinColumn(name = "data_id"))
@MapKeyColumn(name = "name")
@Column(name = "content")
private Map<String, String> tags

经过多次尝试,最后,我只是将 table_tag.data_id 的外键约束添加到父表的主键中。请注意,您应该将 ON DELETE CASCADE 设置为约束。
您可以通过任何方式删除父实体,子元素集合也会被删除。

I met the same problem, and here is my code sample.

@ElementCollection
@CollectionTable(name = "table_tag", joinColumns=@JoinColumn(name = "data_id"))
@MapKeyColumn(name = "name")
@Column(name = "content")
private Map<String, String> tags

After a lot of tries, finally, I just add foreign key constraint for the table_tag.data_id to the parent table's primary key. Notice that you should set ON DELETE CASCADE to the constraint.
You can delete the parent entity by any ways, and the child element collection would be deleted too.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文