2012-04-18 89 views
5

我想用Hibernate从表中检索大约1亿行。我有一个持久实体项目,其中包含一个费用集合(另一个持久实体)。鉴于我遍历结果和访问费用为每个对象,我想急切地收取费用,以避免n + 1问题。用ScrollableResults抓取Hibernate中的集合

我还应该提及,我想将它加入另一个名为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(); 

我的订单类包含提供者字段和项目字段。我得到这个错误:

Caused by: org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list

我想与订单包含项目(使用费预先抓取)和供应商的可滚动列表,结束了。

回答

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

正如你可以看到,当提到抓取关键字,休眠检查,看看是否要求取回装饰领域的父母。 fromElementsForLoad.contains(origin)

他们可能是为了防止你进行冗余连接,这会在性能上花费你很多。这是一件好事,因为如果你从不使用它,没有理由获取关联。

我相信你的情况 - 在新的Order.class中包装Item.class隐藏了你在查询中使用获取装饰字段父项的事实。

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

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

如果你不能验证这一点,我会在下周找到合适的电脑并扩展我的答案。

+0

我认为这个答案是正确的。如果是这样,你应该可以让Hibernate知道你实际上通过改变查询返回一个List而不是构造一个Order来获取'Item':'select i,p from ...'。您将不得不手动创建'订单'。 – 2012-08-11 10:30:21

0

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