从自引用表中删除JPQL

时间:2014-07-30 09:59:10

标签: java hibernate jpa

场景是我有一个表示文件夹结构中的节点的类,它具有ID,名称和指向其父节点的链接。我试图写一些删除所有文件夹的代码,但查询" DELETE FROM Folder"如果文件夹没有以完全正确的顺序删除,则由于完整性限制而不再有效 - 即如果文件夹中有一个引用它的子文件夹,则无法删除该文件夹。

因此需要首先删除没有子节点的文件夹,然后可以删除随后没有子节点的文件夹,反之亦然,直到可以删除根文件夹。

我已尝试为此效果编写循环,但我在查询中苦苦挣扎,代码如下:

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

我从中得到的错误是:

10:56:00,988 INFO [stdout](默认任务-9)休眠:从PT_MESSAGE删除 10:56:01,004 ERROR [org.hibernate.hql.internal.ast.ErrorCounter](默认任务-9)第1:72行:unexpec 特德令牌:不 10:56:01,004 ERROR [org.hibernate.hql.internal.ast.ErrorCounter](默认任务-9)第1:72行:unexpec 特德令牌:不:第1:72行:意外的令牌:不是         在org.hibernate.hql.internal.antlr.HqlBaseParser.deleteStatement(HqlBaseParser.java:296)[h ibernate芯-4.3.1.Final.jar:4.3.1.Final]

我不太了解" NOT EXISTS"似乎是有效的JPA规范的一部分。我究竟做错了什么?还要注意我的持久性提供程序是Hibernate,所以如果我能用JPA或Hibernate以更好的方式做到这一点,那么这也是一种选择。

作为参考,MessageFolder类在这里:

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...
}

2 个答案:

答案 0 :(得分:2)

您的主要问题是字符串连接,例如:

mfparent"
+ "WHERE
由于缺少空格键字符,

会产生无效语句

mfparentWHERE

我的建议是停止在JPQL中拆分String,因为它带来的弊大于利。

答案 1 :(得分:1)

我认为您可以使用 子句中的实现此目的:

query = entityManager.createQuery(
        "DELETE FROM MessageFolder "
        + "WHERE id NOT in ("
        + "SELECT distinct parentFolder.id FROM MessageFolder"
        + ") ");
rowsAffected = query.executeUpdate();