我认为我不会完全理解fetch连接。
我有一个查询,我试图热切地“夸大”两个级别的参考文献。
也就是说,我的A
有一个Collection
B
个B
个C
,B
个A
个B
。已知FetchType.LAZY
集合的大小很小(10-20个顶部)。我想预取这张图。
B
的{{1}}关系标记为C
并且是可选的。 FetchType.LAZY
与SELECT a
FROM A a
LEFT JOIN FETCH a.bs // look, no alias; JPQL forbids it
LEFT JOIN a.bs b // "repeated" join necessary since you can't alias fetch joins
LEFT JOIN FETCH b.c // this doesn't seem to do anything
WHERE a.id = :id
的关系也是可选的A
。
我希望我能做到:
B
当我运行它时,我看到确实提取了LEFT JOIN
s B
集合(我在SQL中看到C
引用C
映射到的表)。
但是,我没有看到提取B
表的证据。
如何从给定的C
预取所有A
以及所有{{1}}和所有{{1}}的“可到达”?我看不到任何办法。
答案 0 :(得分:5)
JPA规范不允许对提取连接进行别名,但有些JPA提供程序会这样做。
EclipseLink从2.4开始。 EclipseLink还允许使用点表示法(即“JOIN FETCH a.bs.c”)进行嵌套连接提取,并支持允许嵌套连接的查询提示“eclipselink.join-fetch”(您可以指定相同提示名称的多个提示) )。
通常,在提取连接上使用别名时需要小心,因为您可能会影响返回的数据。
请参阅, http://java-persistence-performance.blogspot.com/2012/04/objects-vs-data-and-filtering-join.html
答案 1 :(得分:4)
JPA不允许嵌套连接提取,也不允许连接上的别名 fetch,所以这可能是JPA提供者特有的。
在EclipseLink中,您可以指定查询提示以执行嵌套连接 取。
你不能在JPQL中使它递归,你只能充其量只能去 n级。在EclipseLink中,您可以使用@JoinFetch或@BatchFetch 映射使查询递归。
请参阅, http://java-persistence-performance.blogspot.com/2010/08/batch-fetching-optimizing-object-graph.html
来源:http://www.coderanch.com/t/570828/ORM/databases/Recursive-fetch-join-recursively-fetching
答案 2 :(得分:3)
我正在使用Hibernate(这可能是特定的)并且我已经成功了:
SELECT DISTINCT a, b
FROM A a
LEFT JOIN a.bs b
LEFT JOIN FETCH a.bs
LEFT JOIN FETCH b.c
WHERE a.id = :id
(请注意选择列表中的b
)。
这是我发现这对我有用的唯一方法,请注意这会为我返回Object[]
然后我会在代码中过滤它:
(List<A>) q.getResultList().stream().map(pair -> (A) (((Object[])pair)[0])).distinct().collect(Collectors.toList());
答案 3 :(得分:1)
不完全是JPQL,但是您可以使用Criteria查询在纯JPA中实现:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<MyEntity> q = cb.createQuery(MyEntity.class);
Root<MyEntity> root = q.from(MyEntity.class);
q.select(root);
Fetch bsFetch = root.fetch("bs", JoinType.LEFT);
bsFetch.fetch("c", JoinType.LEFT);
对此类型的嵌套提取的支持是特定于供应商的(因为JPA不需要它们这样做),但是eclipselink和hibernate都支持它,这样您的代码就保持与供应商无关。