tags:

views:

45

answers:

2

I'm trying to delete entities which contain lists of Integer, and I'm getting ConstraintViolationExceptions because of the foreign key on the table generated to hold the integers. It appears that the delete isn't cascading to the mapped collection.

I've done quite a bit of searching, but all of the examples I've seen on how to accomplish this are in reference to a mapped collection of other entities which can be annotated; here I'm just storing a list of Integer. Here is the relevant excerpt from the class I'm storing:

@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;
}

I'm deleting the Changes objects using a @NamedQuery:

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");
A: 

After much experimentation, I found that using the Changes.deleteByStatus named query shown in the question simply won't result in the delete being cascaded to the collection table no matter what combination of annotations I tried.

Ultimately I ended up getting all matching entities with the Changes.getByStatus named query and then removing them via the entity manager, which seems to handle the cascading correctly.

    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);
    }

Any other explanations or suggestions are welcome.

Lyle
A: 

An HQL delete doesn't cascade to related entities as per the JPA specs (although some user would like an extended behavior as reported in HHH-695). From the JPA 1.0 specification:

4.10 Bulk Update and Delete Operations

(...)

A delete operation only applies to entities of the specified class and its subclasses. It does not cascade to related entities.

(...)

So you're on your own when using a bulk-delete.

However, in the particular case of a CollectionOfElements which are not entities (and since there is no way to bulk delete the table for the collection), I would have expected the following to work:

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

But unfortunately, it doesn't, the SessionFactory complains with:

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

According to this thread, this sounds like a bug...

So this leave you with the solution you implemented: perform a select, loop and remove the entities.

Pascal Thivent
Thanks for the reference to the spec, that sheds some light on the issue.
Lyle