渴望在 Hibernate 中使用 ScrollableResults 获取集合
Posted
技术标签:
【中文标题】渴望在 Hibernate 中使用 ScrollableResults 获取集合【英文标题】:Eager fetching collections in Hibernate with ScrollableResults 【发布时间】:2012-04-30 08:21:57 【问题描述】:我正在尝试使用 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();
我的 Order 类包含一个 Provider 字段和一个 Item 字段。我收到此错误:
引起:org.hibernate.QueryException:查询指定连接 正在获取,但获取的关联的所有者不存在 选择列表
我想最终得到一个可滚动的订单列表,其中包含项目(急切收取的费用)和提供者。
【问题讨论】:
【参考方案1】:尝试删除left join fetch i.fees f
并在映射中进行急切获取。
【讨论】:
【参考方案2】: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() + "]"
);
如您所见,当提到 fetch 关键字时,hibernate 会检查您是否请求了 fetch 修饰字段父级。 fromElementsForLoad.contains( origin )
他们这样做可能是为了保护您免于进行多余的联接,这会降低您的性能。这是一件好事,因为如果您从不使用关联,就没有理由获取它。
我相信在您的情况下 - 将 Item.class
包装在新的 Order.class
中会隐藏您在查询中使用 fetch 修饰字段父级的事实。
我目前没有调试能力,所以我无法验证这一点。尝试从 SelectClause.class 中调试这一行,看看 fromElementsForLoad
集合包含哪些元素。
如果你想避免 n+1 问题,我建议在查询后初始化 Order.class。您只能选择项目和提供者。
如果您无法验证这一点,我将在下周使用合适的计算机并扩展我的答案。
【讨论】:
我认为这个答案是对的。如果是这样,您应该能够让 Hibernate 知道您实际上正在获取Item
s,方法是更改查询以返回 List
,而不是构造 Order
:select i, p from ...
。然后您必须手动创建Order
s。以上是关于渴望在 Hibernate 中使用 ScrollableResults 获取集合的主要内容,如果未能解决你的问题,请参考以下文章