2012-04-18 90 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並在映射中進行渴望獲取。