使用ScrollableResults渴望在Hibernate中获取集合

Mar*_*tes 5 java hibernate hql eager scrollableresults

我正在尝试使用Hibernate从表中检索大约1亿行.我有一个持久化的实体项目,其中包含一个费用集合(另一个持久化实体).鉴于我迭代结果并访问每个对象的费用,我想急切地获取费用以避免n + 1问题.

我还要提一下,我想将它加入另一个名为Provider的表(一对一映射但没有外键).我试过了:

String query = "select new " + Order.class.getName() 
           + "(i, p) from Item i left join fetch i.fees f, Provider p where "
           + "p.factoryId=i.factoryId and p.factoryRef=i.factoryRef";

return session.createQuery(query).scroll();
Run Code Online (Sandbox Code Playgroud)

我的Order类包含Provider字段和Item字段.我收到此错误:

引起:org.hibernate.QueryException:查询指定的连接提取,但选择列表中不存在获取的关联的所有者

我想最终得到一个可滚动的Order列表,其中包含Item(收取费用)和Provider.

小智 1

这段代码给SelectClause你带来了麻烦:

if ( !fromElementsForLoad.contains( origin ) ) {
                        throw new QueryException(
                                "query specified join fetching, but the owner " +
                                "of the fetched association was not present in the select list " +
                                "[" + fromElement.getDisplayText() + "]"
                        );
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,当提到 fetch 关键字时,hibernate 会检查您是否要求 fetch 修饰字段父级。fromElementsForLoad.contains( origin )

他们这样做可能是为了防止您进行冗余连接,这会降低您的性能。这是一件好事,因为如果您从不使用关联,就没有理由获取它。

我相信在您的情况下 - 将Item.classnewOrder.class包装起来隐藏了您在查询中使用 fetch 修饰字段父级的事实。

我目前没有调试能力,所以无法验证这一点。尝试从 SelectClause.class 中调试这一行,并查看该fromElementsForLoad集合包含哪些元素。

如果你想避免 n+1 问题,我建议在查询后初始化 Order.class。您只能选择项目和提供商。

如果您无法验证这一点,我将在下周找到一台合适的计算机并扩展我的答案。