"NICHT IN `Unterabfrage`" - Anweisung mit JPA Criteria API

Ich bin mit JPA in die Java EE Anwendung und die Kriterien API zur Abfrage meiner Datenbank (PostgreSQL).
Implementiert habe ich einen Baum als Verschluss-Tisch und ich versuche, den root-Knoten.
Hier mein schema (nutzlos Felder weggelassen):

NeedsTreev2     :
id              | primary key

NeedNode        :
id              | primary key
needstree_id    | foreign key references needstreev2(id)

NeedLink        :
ancestor_id     | foreign key references neednode(id)
descendant_id   | foreign key references neednode(id)
needstree_id    | foreign key references needstreev2(id)

Hier ist meine JPA-mapping

public class NeedsTreev2 {
    @Id
    private Long id;
}

public class NeedNode {
    @Id
    private Long id;
}

public class NeedLink {
    @ManyToOne
    private NeedNode ancestor;
    @ManyToOne
    private NeedNode descendant;
    @ManyToOne
    private NeedsTreev2;
}

Den root-Knoten des Baumes sind jene, die nie als Nachkommen, so
hier ist die SQL-Abfrage liefert den Wurzel-Knoten des angegebenen Baum :

SELECT nNode.* FROM neednode nNode
               INNER JOIN needstreev2 nTree
                       ON nNode.needstree_id = nTree.id

               WHERE nTree.id = ?
                 AND nNode.id NOT IN
                (SELECT nLink.descendant_id FROM needlink nLink
                                            WHERE nLink.ancestor_id != nLink.descendant_id)
               ;

Dann habe ich versucht zu übersetzen, mit den Kriterien :

public List<NeedNode> getRootsByTree(NeedsTreev2 tree) {
        List<NeedNode> ret;

        CriteriaBuilder cb = this.getEntityManager().getCriteriaBuilder();
        CriteriaQuery<NeedNode> cq = cb.createQuery(NeedNode.class);

        Root<NeedNode> nNode = cq.from(NeedNode.class);

        /* Here we define the subquery */
        Subquery<NeedNode> sq = cq.subquery(NeedNode.class);
        Root<NeedLink> nLink = sq.from(NeedLink.class);
        sq.where(cb.notEqual(nLink.get(NeedLink_.ancestor), nLink.get(NeedLink_.descendant)));
        sq.select(nLink.get(NeedLink_.descendant));
        /* End of subquery */

        Predicate[] p = {
            cb.equal(nNode.get(NeedNode_.needsTree), tree),
            cb.not(cb.in(nNode).value(sq)) /* This is where the problem occurs */
        };

        cq.where(cb.and(p));

        TypedQuery<NeedNode> query = this.getEntityManager().createQuery(cq);
        ret = query.getResultList();

        return (ret);
    }

Dieser code scheint logisch für mich, aber es gibt eine Ausnahme :

org.eclipse.persistence.exceptions.QueryException
Exception Description: Illegal use of getField() [NEEDNODE.ID] in expression.
Query: ReadAllQuery(referenceClass=NeedNode )

Ich habe auch versucht zu ersetzen cb.not(cb.in(nNode).value(sq)) durch cb.not(nNode.in(sq)) aber es wirft die gleiche Ausnahme.

Ich wohl etwas verpasst, aber ich kann es nicht finden.
Vielen Dank für die Hilfe.

InformationsquelleAutor Unda | 2014-06-12

Schreibe einen Kommentar