删除包含@CollectionOfElements的JPA实体会抛出ConstraintViolationException

时间:2010-06-15 22:14:06

标签: hibernate jpa

我正在尝试删除包含Integer列表的实体,并且我得到了ConstraintViolationExceptions,因为生成的表上的外键用于保存整数。看来删除不会级联到映射的集合。

我已经做了很多搜索,但是我看到的关于如何实现这一点的所有示例都是参考可以注释的其他实体的映射集合;这里我只是存储一个Integer列表。以下是我正在存储的课程的相关摘录:

@Entity
@Table(name="CHANGE_IDS")
@GenericGenerator(
        name = "CHANGE_ID_GEN",
        strategy =  "org.hibernate.id.enhanced.SequenceStyleGenerator",
        parameters = {
                @Parameter(name="sequence_name", value="course_changes_seq"),
                @Parameter(name="increment_size", value="5000"),
                @Parameter(name=" optimizer", value="pooled")
                     }
    )
@NamedQueries ({
    @NamedQuery(
        name="Changes.getByStatus",
        query=  "SELECT c " +
                "FROM DChanges c " +
                "WHERE c.status = :status "),
    @NamedQuery(
            name="Changes.deleteByStatus",
            query=  "DELETE " +
                    "FROM Changes c " +
                    "WHERE c.status = :status ")
})
public class Changes {
    @Id
    @GeneratedValue(generator="CHANGE_ID_GEN")
    @Column(name = "ID")
    private final long id;

    @Enumerated(EnumType.STRING)
    @Column(name = "STATUS", length = 20, nullable = false)
    private final Status status;

    @Column(name="DOC_ID")
    @org.hibernate.annotations.CollectionOfElements
    @org.hibernate.annotations.IndexColumn(name="DOC_ID_ORDER")
    private List<Integer> docIds;
}

我正在使用@NamedQuery删除Changes对象:

final Query deleteQuery = this.entityManager.createNamedQuery("Changes.deleteByStatus");
deleteQuery.setParameter("status", Status.POST_FLIP);
final int deleted = deleteQuery.executeUpdate();
this.logger.info("Deleted " + deleted + " POST_FLIP Changes");

2 个答案:

答案 0 :(得分:2)

根据JPA规范,HQL删除不会级联到相关的实体(尽管某些用户希望HHH-695中报告的扩展行为)。从JPA 1.0规范:

  

4.10批量更新和删除操作

     

(...)

     

删除操作仅适用于   指定类的实体和   它的子类。它没有级联到   相关实体。

     

(...)

因此,在使用批量删除时,您自己就可以了。

但是,在CollectionOfElements不是实体的特定情况下(并且由于无法批量删除集合的表),我希望以下方法能够正常工作:

@Column(name="DOC_ID")
@org.hibernate.annotations.CollectionOfElements
@org.hibernate.annotations.IndexColumn(name="DOC_ID_ORDER")
@OnDelete(action = OnDeleteAction.CASCADE)
private List<Integer> docIds;

但不幸的是,它没有,SessionFactory抱怨:

org.hibernate.MappingException: only inverse one-to-many associations may use on-delete="cascade": com.stackoverflow.q3049451.Changes.docIds

根据this thread,这听起来像个错误......

因此,这将为您提供实施的解决方案:执行选择,循环并删除实体。

答案 1 :(得分:0)

经过多次实验,我发现使用问题中显示的 Changes.deleteByStatus 命名查询只是不会导致删除被级联到集合表,无论我尝试了哪种注释组合

最终,我最终将所有匹配的实体与 Changes.getByStatus 命名查询一起获取,然后通过实体管理器删除它们,实体管理器似乎正确处理了级联。

    final Query query = this.entityManager.createNamedQuery("Changes.getById");
    query.setParameter("status", Status.POST_FLIP);
    List<Changes> changes = query.getResultList();
    for (Changes change : changes) {
        this.entityManager.remove(change);
    }

欢迎任何其他解释或建议。