首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >递归JPA查询?

递归JPA查询?
EN

Stack Overflow用户
提问于 2010-09-03 17:25:51
回答 4查看 29K关注 0票数 16

JPA 2有运行递归查询的机制吗?

下面是我的情况:我有一个实体E,它包含一个整数字段x,它也可能有类型E的子类型,通过@OneToMany映射。我想要做的是通过主键找到一个E,得到它的值x,以及它的所有后代的x值。是否有任何方法在一个查询中做到这一点?

我正在使用Hibernate 3.5.3,但我不希望对Hibernate API有任何明确的依赖。

编辑:根据条目,Hibernate没有这个特性,或者至少在三月份没有。因此,JPA不太可能拥有它,但我想确定一下。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-09-03 21:00:22

使用简单的邻接模型,其中每一行包含对其父行的引用,它将引用同一表中的另一行,这与JPA不太好地合作。这是因为JPA不支持使用Oracle CONNECT BY子句或SQL标准WITH语句生成查询。如果没有这两个子句中的任何一个,就不可能真正使邻接模型有用。

然而,有几种其他方法可以应用于这个问题来模拟这个问题。第一个是物化路径模型。这是将到节点的完整路径平坦为单个列的地方。表定义的扩展如下:

代码语言:javascript
运行
复制
CREATE TABLE node (id INTEGER,
                   path VARCHAR, 
                   parent_id INTEGER REFERENCES node(id));

要插入一棵节点树,如下所示:

代码语言:javascript
运行
复制
INSERT INTO node VALUES (1, '1', NULL);  -- Root Node
INSERT INTO node VALUES (2, '1.2', 1);   -- 1st Child of '1'
INSERT INTO node VALUES (3, '1.3', 1);   -- 2nd Child of '1'
INSERT INTO node VALUES (4, '1.3.4', 3); -- Child of '3'

因此,要获取Node '1‘及其所有子节点,查询如下:

代码语言:javascript
运行
复制
SELECT * FROM node WHERE id = 1 OR path LIKE '1.%';

要将其映射到JPA,只需将“path”列作为持久对象的属性即可。然而,您将不得不做簿记保持‘路径’字段的最新。JPA/Hibernate不会为您这样做。例如,如果将节点移动到不同的父节点,则必须同时更新父引用并确定来自新父对象的新路径值。

另一种方法称为嵌套集模型,它要复杂得多。也许最好的所述由它的发起人(而不是由我逐字添加)。

还有第三种方法叫做嵌套区间模型( Nested ),但是这严重依赖于存储过程来实现。

对这个问题的一个更完整的解释是在SQL的艺术的第7章中描述的。

票数 29
EN

Stack Overflow用户

发布于 2016-02-02 13:48:19

对我来说,这篇文章中最好的答案似乎是一次大规模的工作攻击。我已经处理了一些数据模型,在这些模型中,优秀的工程师认为将DB字段中的Tree Hiarchies编码为文本是个不错的主意,比如:“欧洲-维京-英国,Shop1 1-John”,以及这些表中的大量数据。不出所料,表单MyHackedTreeField的查询性能就像'parentHierharchy%‘一样。要解决这类问题,最终需要在树的内存缓存中创建hiearchies和许多其他的.

如果您需要运行递归查询,而且数据量不是很大.让您的生活变得简单,只需加载运行计划所需的DB字段。并在java中编写递归代码。除非您有充分的理由这样做,否则不要在DB中这样做。

而且,即使您拥有的数据量很大,您也很可能将您的问题细分为独立的递归树批,并在不需要一次加载所有数据的情况下对它们进行处理。

票数 9
EN

Stack Overflow用户

发布于 2020-05-25 07:25:23

我知道这个问题很古老,但由于它是在另一个问题中链接起来的,所以我想对此进行更新,因为熊熊提供了对在JPA模型之上使用递归CTE的支持。

Blaze-Persistence是JPA之上的一个查询生成器,它支持JPA模型上的许多高级DBMS特性。要建模CTE或递归CTE,首先需要引入一个CTE实体,该实体对CTE的结果类型进行建模。

代码语言:javascript
运行
复制
@CTE
@Entity
public class GroupCTE {
  @Id Integer id;
}

获取组层次结构的查询如下所示

代码语言:javascript
运行
复制
List<Group> groups = criteriaBuilderFactory.create(entityManager, Group.class)
  .withRecursive(GroupCTE.class)
    .from(Group.class, "g1")
    .bind("id").select("g1.id")
    .where("g1.parent").isNull()
  .unionAll()
    .from(Group.class, "g2")
    .innerJoinOn(GroupCTE.class, "cte")
      .on("cte.id").eq("g2.parent.id")
    .end()
    .bind("id").select("g2.id")
  .end()
  .from(Group.class, "g")
  .fetch("groups")
  .where("g.id").in()
    .from(GroupCTE.class, "c")
    .select("c.id")
  .end()
  .getResultList();

这将呈现为如下所示的SQL

代码语言:javascript
运行
复制
WITH RECURSIVE GroupCTE(id) AS (
    SELECT g1.id
    FROM Group g1
    WHERE g1.parent_group_id IS NULL
  UNION ALL
    SELECT g2.id
    FROM Group g2
    INNER JOIN GroupCTE cte ON g2.parent_group_id = cte.id
)
SELECT *
FROM Group g
LEFT JOIN Group gsub ON gsub.parent_group_id = g.id
WHERE g.id IN (
  SELECT c.id
  FROM GroupCTE c
)

您可以在文档:US/index.html#递归-ctes中找到关于递归CTEs的更多信息。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3638082

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档