The scenario is that I have a class that represents a node in a folder structure, which has an ID, a name and a link to its parent. I'm trying to write some code that deletes all the folders, however the query "DELETE FROM Folder" no longer works because of integrity constraints if the folders are not deleted in exactly the right order - ie a folder cannot be deleted if it has a child that references it.
So what needs to happen is that the folders with no children need to be deleted first, and then the folders that are subsequently left with no children can be deleted, and so on iteratively until the root folders can be deleted.
I've tried writing a loop to this effect but I'm struggling with the query, the code is like this:
int rowsAffected = -1;
while(rowsAffected != 0) {
query = entityManager.createQuery(
"DELETE FROM MessageFolder mfparent"
+ "WHERE NOT EXISTS ("
+ "FROM MessageFolder mfchild"
+ "WHERE mfchild.parentId = mfparent.id"
+ ") ");
rowsAffected = query.executeUpdate();
}
The error I get from this is:
10:56:00,988 INFO [stdout] (default task-9) Hibernate: delete from PT_MESSAGE 10:56:01,004 ERROR [org.hibernate.hql.internal.ast.ErrorCounter] (default task-9) line 1:72: unexpec ted token: NOT 10:56:01,004 ERROR [org.hibernate.hql.internal.ast.ErrorCounter] (default task-9) line 1:72: unexpec ted token: NOT: line 1:72: unexpected token: NOT at org.hibernate.hql.internal.antlr.HqlBaseParser.deleteStatement(HqlBaseParser.java:296) [h ibernate-core-4.3.1.Final.jar:4.3.1.Final]
Which I don't quite understand as "NOT EXISTS" seems to be valid as part of the JPA spec. What am I doing wrong? Also to note that my persistence provider is Hibernate, so if I can do this in a better way with either JPA or Hibernate, that is also an option.
For reference the MessageFolder class is here:
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name="PT_MESSAGE_FOLDER")
public class MessageFolder {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long id;
private String name;
@OneToMany(mappedBy="messageFolder", targetEntity=Message.class,
cascade=CascadeType.ALL, fetch=FetchType.EAGER)
private List<Message> messages;
@OneToOne
@JoinColumn(name="parentId", referencedColumnName="id")
private MessageFolder parentFolder;
public MessageFolder() {
messages = new ArrayList<>();
}
//getters.. setters...
}