HQL递归,我该怎么做?

发布于 2024-08-26 04:14:51 字数 343 浏览 6 评论 0原文

我有一个树结构,其中每个 Node 都有一个父级和一个 Set。孩子们。每个节点都有一个 String title,我想在选择 Set的位置进行查询。 Titles,是该节点和所有父节点的标题。我该如何编写这个查询?

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

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

干杯

尼克

I have a tree structure where each Node has 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?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

下雨或天晴 2024-09-02 04:14:51

您无法使用 HQL 进行递归查询。 查看此内容。正如那里所说,它甚至不是标准 SQL。您有两个选择:

  • 编写特定于供应商的递归本机 SQL 查询
  • 进行多个查询。例如:

    // 使用查询获取第一个节点
    while (currentNode.parent != null) {
       Query q = //创建查询
       q.setParameter("id", currentNode.getParentId());
       节点 currentNode = (Node) q.getSingleResult();
       节点.add(当前节点); // 这是集合
    }
    

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

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

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

I'd definitely go for the 2nd option.

尘曦 2024-09-02 04:14:51

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

select n from Node n
left join fetch n.Children

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.

select n from Node n
left join fetch n.Children
栀梦 2024-09-02 04:14:51

我知道这个问题很旧,但由于它在另一个问题中链接,我想对此进行更新,如 Blaze-Persistence 为在 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.com/documentation/core/manual/en_US/index.html#recursive-ctes

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-Persistence offers support for working with recursive CTEs on top of the JPA model.

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.

@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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文