递归 JPA 查询?

2022-09-03 04:08:45

JPA 2 是否有任何运行递归查询的机制?

这是我的情况:我有一个实体E,其中包含一个整数字段x。它也可能具有E型子级,通过@OneToMany映射。我想做的是通过主键找到一个E,并获取其x的值,以及其所有后代的x值。有没有办法在单个查询中执行此操作?

我使用的是Hibernate 3.5.3,但我宁愿不要对Hibernate API有任何明确的依赖关系。


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


答案 1

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

但是,还有其他几种方法可以对此问题进行建模,这些方法可以应用于此问题。第一个是具体化路径模型。这是将节点的完整路径平展为单个列的位置。表定义按如下方式扩展:

CREATE TABLE node (id INTEGER,
                   path VARCHAR, 
                   parent_id INTEGER REFERENCES node(id));

插入节点树看起来像这样:

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'

因此,要获取节点“1”及其所有子节点,查询为:

SELECT * FROM node WHERE id = 1 OR path LIKE '1.%';

要将其映射到 JPA,只需将“path”列设置为持久对象的属性即可。但是,您必须进行簿记以保持“路径”字段的最新状态。JPA/Hibernate 不会为你做这件事。例如,如果将节点移动到其他父对象,则必须更新父引用并从新的父对象确定新的路径值。

另一种方法称为嵌套集模型,它稍微复杂一些。可能最好由其发起人描述(而不是由我逐字添加)。

还有第三种方法称为嵌套间隔模型,但是这种方法在很大程度上依赖于存储过程来实现。

对这个问题的更完整的解释在《SQL的艺术》的第7章中进行了描述。


答案 2

这篇文章中最好的答案对我来说似乎是一个巨大的解决方法。我已经不得不处理数据模型,其中聪明的工程师决定将数据库字段中的树层次结构编码为文本(例如:“欧洲|英国|商店1|约翰“,并在这些表中有大量的数据。不超然,MyHackedTreeField形式的查询性能像“parentHierharchy%”的杀手。解决此类问题最终需要创建树层次结构的内存缓存以及许多其他问题...

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

即使您拥有的数据量很大,您也很可能可以将问题细分为不消耗的递归树批处理,并一次处理一个,而无需一次加载所有数据。


推荐