JPA / Hibernate查询:使用subselect急切加载

时间:2015-03-30 19:56:14

标签: java hibernate jpa eclipselink jpa-2.0

情境:"家长"实体有多个" Child"实体(@OneToMany,@ Lazy) - 双向关系。实体上没有外键(" Child#parentId")字段。

目标:通过使用子选择检索完全加载的父集合来避免N + 1问题。如果我理解Subselect的理论,这是我的目标(2个结果SQL查询):

select * from Parent ...;
select * from Child where parent_id in ...;


问题1 :实现这一目标的最佳做法是什么?你能提供JPQL / HSQL和Criteria中的例子吗?

问题2(奖金):API可以将第二个查询分区管理为"批次" - 例如限制批量为500:如果第一个查询加载1000个父项,2a。加载500个父母的孩子,2b。为下一个500加载。


我试过: 两者都导致SQL JOIN,似乎在没有JOIN的情况下我不能使用Child的外键。

// 2nd query:
criteria
.createAlias("parent", "p")
.add(Property.forName("p.id")
        .in(parentCriteria.setProjection(Projections.property("id"))))
.list();

// 2nd query (manual):
criteria
.createAlias("parent", "p")
.add(Property.forName("p.id").in(parentIdList))
.list();

更新(2015-04-05)

我通过提示检查了它在EclipseLink中的确实作用:

query.setHint("eclipselink.batch.type", "EXISTS");

此链接http://blog.ringerc.id.au/2012/06/jpa2-is-very-inflexible-with-eagerlazy.html表明这不可能通过Hibernate进行,并建议手动提取。但是我无法理解如何通过HQL或Criteria实现它,特别是如何获取不在Entity上但仅存在于Database上的child.parent_id列。也就是说,避免因child.parent.id而导致的JOIN。

1 个答案:

答案 0 :(得分:0)

要避免N + 1个查询,您可以使用

注释关系
@BatchFetch(BatchFetchType.JOIN)  //in eclipselink or
@BatchSize //in hibernate.

在内部查询中,您可以添加fetch to join子句:

select p from Parent p join fetch p.children c where ...

您还可以添加查询提示

query.setHint("eclipselink.batch", "p.children");

或使用EntityGraphs。