HQL递归,我怎么做?

问题描述 投票:15回答:3

我有一个树形结构,其中每个 Node 有一个父母和一个 Set<Node> children. 每个节点有一个 String title,我想做一个查询,我选择了 Set<String> titles,是这个节点和所有父节点的标题。如何写这个查询?

对单个标题的查询是这样的,但就像我说的,我希望它能扩展到整个父节点的分支。

SELECT node.title FROM Node node WHERE node.id = :id

干杯

java hibernate orm recursion hql
3个回答
14
投票

你不能用HQL做递归查询。请看这个. 而且正如那里所说,它甚至不是标准的SQL。你有两个选择。

  • 编写一个特定厂商的递归本地 SQL查询
  • 进行多次查询。比如说。

    // obtain the first node using your query
    while (currentNode.parent != null) {
       Query q = //create the query
       q.setParameter("id", currentNode.getParentId());
       Node currentNode = (Node) q.getSingleResult();
       nodes.add(currentNode); // this is the Set
    }
    

我肯定会选择第二种方案。


9
投票

虽然不可能写出你所要求的递归查询,但可以用HQL热切地获取层次结构;这样做至少可以让你在内存中走树,而不用为每一层打数据库。

select n from Node n
left join fetch n.Children

0
投票

我知道这个问题是老问题了,但由于在另一个问题中链接过,我想给大家更新一下,因为 燃烧-持久性 提供了对JPA模型之上的递归CTE的支持。

Blaze-Persistence是一个JPA之上的查询构建器,它支持JPA模型之上的许多高级DBMS功能。要对CTE或递归CTE进行建模,也就是我们这里所需要的,首先需要引入一个CTE实体,对CTE的结果类型进行建模。

@CTE
@Entity
public class NodeCTE {
  @Id Integer id;
}

你的例子中的一个查询可以看起来像下面这样

List<String> titles = criteriaBuilderFactory.create(entityManager, String.class)
  .withRecursive(NodeCTE.class)
    .from(Node.class, "n1")
    .bind("id").select("n1.id")
    .where("n1.id").eq(nodeId)
  .unionAll()
    .from(Node.class, "n2")
    .innerJoinOn(NodeCTE.class, "cte")
      .on("cte.id").eq("n2.parent.id")
    .end()
    .bind("id").select("n2.id")
  .end()
  .from(Node.class, "n")
  .select("n.title")
  .where("n.id").in()
    .from(NodeCTE.class, "c")
    .select("c.id")
  .end()
  .getResultList();

这在SQL中的表现是这样的。

WITH RECURSIVE NodeCTE(id) AS (
    SELECT n1.id
    FROM Node n1
    WHERE n1.parent_id = :id
  UNION ALL
    SELECT n2.id
    FROM Node n2
    INNER JOIN NodeCTE cte ON n2.parent_id = cte.id
)
SELECT n.title
FROM Node n
WHERE n.id IN (
  SELECT c.id
  FROM NodeCTE c
)

你可以在文档中找到更多关于递归CTE的信息。https:/persistence.blazebit.comdocumentationcoremanualen_USindex.html#recursive-ctes。

© www.soinside.com 2019 - 2024. All rights reserved.