Deleting JPA entity containing @CollectionOfElements throws ConstraintViolationException
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");
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.
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.
精彩评论