gpt4 book ai didi

java - "NOT IN ` 子查询 `"语句与 JPA Criteria API

转载 作者:行者123 更新时间:2023-11-30 06:18:40 24 4
gpt4 key购买 nike

我在我的 Java EE 应用程序中使用 JPA 和 Criteria API 来查询我的数据库 (PostgreSQL)。我将一棵树实现为闭包表,并试图获取根节点。这是我的架构(省略了无用的字段):

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)

这是我的 JPA 映射

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

树的根节点是那些从未被用作后代的节点,所以这是返回指定树的根节点的 SQL 查询:

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

然后我尝试用 Criteria 翻译它:

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

这段代码对我来说似乎是合乎逻辑的,但它抛出了一个异常:

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

我还尝试用 cb.not(nNode.in(sq)) 替换 cb.not(cb.in(nNode).value(sq))但它抛出相同的异常。

我可能错过了什么,但我找不到了。感谢您的帮助。

最佳答案

我就是这样解决问题的:我主要在子查询中选择了 NeedNode.id 而不是整个对象。这样,IN 语句就可以工作了。

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

Subquery<Long> sq = cq.subquery(Long.class);
Root<NeedLink> nLink = sq.from(NeedLink.class);
Join<NeedLink, NeedNode> d = nLink.join(NeedLink_.descendant, JoinType.INNER);
sq.where(cb.notEqual(nLink.get(NeedLink_.ancestor), nLink.get(NeedLink_.descendant)));
sq.select(d.get(NeedNode_.id));
sq.distinct(true);

Predicate[] p = {
cb.equal(nNode.get(NeedNode_.needsTree), tree),
nNode.get(NeedNode_.id).in(sq).not()
};

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

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

return (ret);
}

因此代码需要一个Join 变量和子查询来返回Long 而不是NeedNode。它以这种方式工作,但我不明白为什么它不像问题中所写的那样工作。 IMO,使子查询选择 id 使 Criteria 查询失去了它的“类型安全”功能。

关于java - "NOT IN ` 子查询 `"语句与 JPA Criteria API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24183862/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com