2011-06-23 44 views
1

我有2點簡單的模型:不匹配HQL結果左Hibernate的標準API的結果連接抓取

class Parent { 
    Long id; //auto generated sequence and primary key 
    String name; 
    Set<Child> children; 
} 

class Child { 
    String name; 
    Long parent_id; //foreign key 
} 

我有一個HQL這樣的查詢:

FROM Parent p 
    left join fetch p.children as children 
WHERE p.name = 'John' 

'孩子' 是一個集合(在Parent模型中設置'Child'模型。

如果'John'有2個孩子,通過執行單個查詢,上面查詢的結果給出了每個有2個孩子的2個父母(相同引用)的列表。

我想實現通過標準API同象下面這樣:

Criteria c = session.createCriteria(Parent.class); 
c.setFetchMode("children", FetchMode.JOIN); 
c.createCriteria("children", Criteria.LEFT_JOIN); 
c.add(Restrictions.eq("name", "John")); 
c.scroll(); 

有了上面的代碼中,我得到2個父實例(同一基準)的列表中,只有1名兒童元素(而不是預期的2 )bu執行單個sql查詢。

我在做什麼錯誤的API?當我看到生成的sql時,它是一樣的。

+0

看起來這與'c.scroll()'和'c.list()'有關,而不是HQL和Criteria API之間的區別。當我發佈這個問題時,我使用'query.list()'作爲HQL,'c.scroll()'作爲Criteria API。現在我嘗試了所有4種組合,發現只有c.scroll()以意想不到的方式行事。我不明白爲什麼或如何解決它。 – Bhargava

+0

看起來在'scroll'期間,'session'只查看緩存中的父標識符,而沒有用新的子關聯來更新它。但是'list'似乎正在用新的子關聯更新緩存的父對象。我的推理是,它不希望爲同一個對象提供2種不同的狀態,因此如果在進一步滾動期間再次遇到緩存對象,它不會更新緩存對象。我對嗎?我試過'c.setCacheable(false)'/'c.setCacheable(true); c.setCacheMode(CacheMode.IGNORE/REFRESH)'但不起作用。 – Bhargava

+0

它看起來像我需要滾動有序的父列表和訂購與2查詢的子列表,他們合併它們programmatic-ally冬眠外。我想知道是否有更好的方法。 – Bhargava

回答

0

我有類似的情況,在這裏是等價(在我的處境至少)代碼:

Criteria c = session.createCriteria(Parent.class); 
c.setFetchMode("children", FetchMode.JOIN); 
c.add(Restrictions.eq("name", "John")); 

List<Parent> list = c.list(); 
Iterator<Parent> iter = list.iterator(); 

我的印象中,行 c.scroll();強制相似的行爲c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

+0

其實,那不是我所觀察到的。如果應用了'DISTRINCT_ROOT_ENTITY'變形器,'c.list()'返回一個具有2個子元素的父列表實例。 'c.scroll()'完全不受這個結果轉換器的影響。 – Bhargava

+0

此外,我看到你的代碼沒有指定一個左連接,我猜測默認情況下自然連接是通過休眠來選擇的。 – Bhargava

+0

給出一個一對多的關係,左外連接是我在設置'FetchMode.JOIN'時觀察到的默認行爲 – iliaden

1

我有同樣的問題,並通過Hibernate代碼調試後,我認爲這是一個Hibernate的錯誤,而不是你做錯的任何事情。

它被修復爲this Hibernate issue,但我們的Criteria仍然在可滾動結果中返回不完整的子集合。我發現在Loader類中有一些邏輯決定是否使用FetchingScrollableResultsImpl來正確處理行,而在CriteriaLoader上它從來沒有這樣做,因爲needsFetchingScroll()總是返回false。然而QueryLoader確實在使用聯合抓取時使用它,這就是爲什麼將我們的Criteria轉換爲HQL解決了我們的問題。

我打算提交一個Hibernate的bug來實現CriteriaLoader.needsFetchingScroll()