5

我正在尝试使用 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:查询指定连接提取,但提取关联的所有者不存在于选择列表中

我想最终得到一个可滚动的订单列表,其中包含项目(急切收取的费用)和提供者。

4

2 回答 2

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() + "]"
                        );

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

他们可能这样做是为了保护您免于进行多余的连接,这会在性能上花费您很多。这是一件好事,因为如果您从不使用它,就没有理由获取关联。

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

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

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

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

于 2012-08-11T10:04:56.037 回答
0

尝试删除left join fetch i.fees f并在映射中进行急切获取。

于 2012-08-11T06:11:45.200 回答