java HQL 递归,我该怎么做?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2486757/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 21:25:41  来源:igfitidea点击:

HQL recursion, how do I do this?

javahibernateormrecursionhql

提问by niklassaers

I have a tree structure where each Nodehas a parent and a Set<Node> children. Each Node has a String title, and I want to make a query where I select Set<String> titles, being the title of this node and of all parent nodes. How do I write this query?

我有一个树结构,其中每个Node都有一个父级和一个Set<Node> children. 每个节点都有一个String title, 我想在我选择的地方进行查询Set<String> titles,作为这个节点和所有父节点的标题。如何编写此查询?

The query for a single title is this, but like I said, I'd like it expanded for the entire branch of parents.

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

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

Cheers

干杯

Nik

尼克

采纳答案by Bozho

You can't do recursive queries with HQL. See this. And as stated there it is not even standard SQL. You have two options:

您不能使用 HQL 进行递归查询。看到这个。正如那里所说,它甚至不是标准的 SQL。您有两个选择:

  • write a vendor-specific recursive native SQL query
  • make multiple queries. For example:

    // 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
    }
    
  • 编写特定于供应商的递归原生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
    }
    

I'd definitely go for the 2nd option.

我肯定会选择第二个选项。

回答by James Gregory

While it isn't possible to write the recursive query you're asking for, it is possible to eager fetch the hierarchy with HQL; doing this would at least allow you to walk the tree in memory without hitting the database for each level.

虽然无法编写您所要求的递归查询,但可以使用 HQL 预先获取层次结构;这样做至少可以让您在内存中遍历树,而无需为每个级别访问数据库。

select n from Node n
left join fetch n.Children

回答by Christian Beikov

I know this question is old, but as it was linked in a different question, I wanted to give an update on this, as Blaze-Persistenceoffers support for working with recursive CTEs on top of the JPA model.

我知道这个问题很旧,但由于它与另一个问题相关联,因此我想对此进行更新,因为Blaze-Persistence支持在 JPA 模型之上使用递归 CTE。

Blaze-Persistence is a query builder on top of JPA which supports many of the advanced DBMS features on top of the JPA model. To model CTEs or recursive CTEs, which is what you need here, you first need to introduce a CTE entity that models the result type of the CTE.

Blaze-Persistence 是一个基于 JPA 的查询构建器,它支持基于 JPA 模型的许多高级 DBMS 功能。要对 CTE 或递归 CTE 进行建模,这正是您在这里需要的,您首先需要引入一个 CTE 实体,该实体对 CTE 的结果类型进行建模。

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

A query for your example could look like the following

您的示例的查询可能如下所示

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

This renders to SQL looking like the following

这将呈现给 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
)

You can find out more about recursive CTEs in the documentation: https://persistence.blazebit.com/documentation/core/manual/en_US/index.html#recursive-ctes

您可以在文档中找到有关递归 CTE 的更多信息:https: //persistence.blazebit.com/documentation/core/manual/en_US/index.html#recursive-ctes