逆袭的领结 · [Solved] Spring Data ...· 6 天前 · |
被表白的八宝粥 · VSIXInstaller.NoApplic ...· 2 月前 · |
直爽的八宝粥 · 联想_笔记本_联想商城· 2 月前 · |
酷酷的火锅 · Intel Core i7-13650HX ...· 3 月前 · |
安静的领带 · 电动汽车高压系统的组成部件与功能介绍· 4 月前 · |
JPA 2有运行递归查询的机制吗?
下面是我的情况:我有一个实体E,它包含一个整数字段x,它也可能有类型E的子类型,通过@OneToMany映射。我想要做的是通过主键找到一个E,得到它的值x,以及它的所有后代的x值。是否有任何方法在一个查询中做到这一点?
我正在使用Hibernate 3.5.3,但我不希望对Hibernate API有任何明确的依赖。
编辑:根据 这 条目,Hibernate没有这个特性,或者至少在三月份没有。因此,JPA不太可能拥有它,但我想确定一下。
发布于 2010-09-03 21:00:22
使用简单的 邻接模型 ,其中每一行包含对其父行的引用,它将引用同一表中的另一行,这与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'
因此,要获取Node '1‘及其所有子节点,查询如下:
SELECT * FROM node WHERE id = 1 OR path LIKE '1.%';
要将其映射到JPA,只需将“path”列作为持久对象的属性即可。然而,您将不得不做簿记保持‘路径’字段的最新。JPA/Hibernate不会为您这样做。例如,如果将节点移动到不同的父节点,则必须同时更新父引用并确定来自新父对象的新路径值。
另一种方法称为 嵌套集模型 ,它要复杂得多。也许最好的 所述 由它的发起人(而不是由我逐字添加)。
还有第三种方法叫做嵌套区间模型( Nested ),但是这严重依赖于存储过程来实现。
对这个问题的一个更完整的解释是在 SQL的艺术 的第7章中描述的。
发布于 2016-02-02 13:48:19
对我来说,这篇文章中最好的答案似乎是一次大规模的工作攻击。我已经处理了一些数据模型,在这些模型中,优秀的工程师认为将DB字段中的Tree Hiarchies编码为文本是个不错的主意,比如:“欧洲-维京-英国,Shop1 1-John”,以及这些表中的大量数据。不出所料,表单MyHackedTreeField的查询性能就像'parentHierharchy%‘一样。要解决这类问题,最终需要在树的内存缓存中创建hiearchies和许多其他的.
如果您需要运行递归查询,而且数据量不是很大.让您的生活变得简单,只需加载运行计划所需的DB字段。并在java中编写递归代码。除非您有充分的理由这样做,否则不要在DB中这样做。
而且,即使您拥有的数据量很大,您也很可能将您的问题细分为独立的递归树批,并在不需要一次加载所有数据的情况下对它们进行处理。
发布于 2020-05-25 07:25:23
我知道这个问题很古老,但由于它是在另一个问题中链接起来的,所以我想对此进行更新,因为 熊熊 提供了对在JPA模型之上使用递归CTE的支持。
Blaze-Persistence是JPA之上的一个查询生成器,它支持JPA模型上的许多高级DBMS特性。要建模CTE或递归CTE,首先需要引入一个CTE实体,该实体对CTE的结果类型进行建模。
@CTE
@Entity
public class GroupCTE {
@Id Integer id;
}
获取组层次结构的查询如下所示
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
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 *
逆袭的领结 · [Solved] Spring Data JPA :QueryCreationException: Could not create query for public abstract method 6 天前 |
直爽的八宝粥 · 联想_笔记本_联想商城 2 月前 |
安静的领带 · 电动汽车高压系统的组成部件与功能介绍 4 月前 |