2009-02-26 63 views
13

我有以下實體結構:業務 - >廣告系列 - >促銷,其中ONE業務可以有許多廣告系列,一個廣告系列可以有許多促銷活動。一對多關係都被聲明爲LAZY。在我的代碼的一個地方,我需要預先抓取從商務兼具收藏,所以我做的:JPA:請幫助理解「加入獲取」

Query query = entityManager.createQuery("select b from Business b " + 
      "left join fetch b.campaigns c " + 
      "left join fetch c.promotions where b.id=:id"); 
query.setParameter("id", b.getId()); 
business = (Business) query.getResultList().get(0); 

但是,查詢返回包含在它4個業務對象,所有4個對象指的是一個結果列表相同的業務實例。在我的數據庫中,該業務下有3個廣告系列,所有3個廣告系列都有3個廣告系列。

我有兩個問題:

  1. 起初,我用清單包含關係的許多方面,但是當程序運行時,我得到「org.hibernate.HibernateException:不能同時獲取多袋「例外。然後我GOOGLE了這個異常,它看起來像我必須使用Set,而不是List。所以我把集合改爲Set,它工作。有人能告訴我爲什麼List在這種情況下不起作用嗎?

  2. 我期待查詢返回單個結果,因爲它查詢的是主鍵的id,因此應該只返回單個結果。但事實證明,它返回列表中的4個實例。這是一個問題嗎?或者這是預期的行爲?

任何幫助將不勝感激。

回答

20

生成的SQL看起來是這樣的:

select * from Business b 
left outer join campaigns c on c.business_id = b.id 
left join promotions p on p.campaign_id = c.id 
where b.id=:id 

內部Hibernate將只有一個業務實例,但重複項將保留在結果集中。這是預期的行爲。這將只返回獨特的結果,維護插入順序

Collection result = new LinkedHashSet(query.getResultList()); 

:您需要可以通過使用DISTINCT子句要麼來達到的行爲,或使用LinkedHashSet篩選結果。

只要您試圖以有序方式(可能重複項目)急於獲取多個集合,就會發生「org.hibernate.HibernateException:無法同時獲取多個行李」。如果考慮生成的SQL,這確實有意義。 Hibernate無法知道重複的對象是由連接還是由子表中的實際重複數據引起的。看看this有一個很好的解釋。

+1

向查詢中添加「distinct」確實有效。謝謝。 – 2009-02-27 02:12:14

3
  1. 由於笛卡爾積和列表可以有多餘的元素,人們並沒有意識到這一點,所以休眠人員開始拋出這個錯誤來強迫人們使用Set而不是List來避免這個問題。來源1
0

另一個解決方法,而不是使用Set是使用兩個查詢來獲取數據: - 第一個加載活動及其相關的業務促銷。然後使用提取加載商業及其廣告系列

Query query1 = entityManager.createQuery("select c from Business b join b.campaigns c left join fetch c.promotions where b.id=:id"); 
    query1.setParameter("id", b.getId()); 
    query1.getResultList(); 

    Query query2 = entityManager.createQuery("select b from Business b left join fetch  b.campaigns where b.id=:id"); 
    query2.setParameter("id", b.getId()); 
    business = (Business) query2.getResultList().get(0);