2009-10-12 92 views
1

假設我有實體A,B,C,並且每個A都有許多B和C實體。我想查詢基於一些criterea的A實體的負載,並且我知道我將訪問每個A返回的所有B和C實體。如何有效地查詢三個相關表(JPA-QL)

select a from A as a join fetch a.b join fetch a.c這樣的東西一開始似乎是有意義的,但是如果B和C實體的數量很大,這會產生一個巨大的產品。將此擴展到另一個關聯實體會使查詢完全不合理。

如果我將JPA留給自己的設備,那麼當它想要訪問B和C實體時,我最終會得到n + 1個選擇。

我以爲我會做的是查詢一個連接抓取B,然後一個連接抓取C,但這不起作用,因爲它給我兩個List<A>每個結果只有一半的信息。

這是一個非常簡單的SQL查詢語句,我很失望,沒有一個明顯的方法來處理這個問題。我錯過了什麼嗎?

提供商是toplink必需品

回答

0

我想知道你爲什麼說這在SQL中很簡單。你不也有笛卡爾產品嗎?


使用Hibernate的提供商JPA,你提到的作品一個選項:

查詢連接抓取B,那麼A連接抓取ç

你有相同的兩個列表值,你只使用一個,它很好(你只需要左連接)。


在Hibernate中,您還可以要求在第二個查詢中獲取缺失的數據。使用fetch="subselect"

https://www.hibernate.org/315.html


修訂樓主的意見後:

在java中,你也可以手工做到這一點。

  1. 將它們的B的集合取回到名爲entityAs的列表中。
  2. 使用它們的Cs集合(重用部分查詢或使用ID)獲取As。
  3. 爲第二個查詢(用於性能,避免內部循環)創建一個數據結構Map>。
  4. 環路上的列表entityAs,使用地圖設置集CS中的每個實例A.

這將有不錯的表現也。

如果你多次運行這個需求,你可以寫一個參數化方法來爲你做這個,所以你只需要編寫一次。

正如評論由原始的海報,你需要分離從entityAs所有A實體修改它們之前,以確保不會有任何更新發送到數據庫...

+0

「我想知道你爲什麼說這在SQL中很簡單,你是不是也有笛卡爾產品?」 如果我用一個查詢做了它,當然。我的意思是我可以輕鬆地做兩個查詢並將兩者的結果一起使用。 我知道冬眠可以做到這一點,但我使用的是toplink。 – Draemon 2009-10-12 13:42:29

+0

@Draemon好的,謝謝澄清SQL部分。 – KLE 2009-10-12 13:57:54

+1

感謝您的更新 - 這與我現在正在嘗試的類似。我是否正確地假設我必須首先分離所有實體,否則第4步會將所有As標記爲髒,並在提交時導致混亂? – Draemon 2009-10-12 14:22:24

1

JPA至少應該提及對象。事實上,你並沒有暗示你不會充分利用JPA。

如果你有一個遺留模式,並且對象模型沒有意義,也許你不應該使用JPA。

JPA並不打算成爲SQL的替代品。它解決了那個對象關係不匹配問題。如果你沒有對象,只需下拉到JDBC和SQL。

我不知道你的表格代表什麼,但如果你在考慮物體,你應該談論1:m和m:n的關係。一旦你有了這些,你可以使用緩存,懶惰和渴望獲取來優化填充對象。

更新:編寫查詢,以便每個產品都有其選項和價格列表爲1:m的關係,並進行提前取用。這將避免(n + 1)問題。

你怎麼能說關係和渴望提取在這裏沒有幫助?

嘗試在對象中表達關係並讓JPA向您展示它生成的SQL並將其與您所寫的內容進行比較。如果滿意的話,就去做吧。如果沒有,請下載到JDBC並查看您是否可以做得更好。

+0

嘛實體對象,不是他們。 ORM的要點是你在Java端有對象,而在DB端有關係模型。我想查詢幾個產品及其相關的選項和價目表,我不希望它產生病態效率低下的查詢。緩存和懶惰/渴望提取在這裏沒有幫助 - 我需要1個查詢而不是n + 1。我知道前面我會需要所有的數據。 – Draemon 2009-10-12 13:46:18

+0

@Draemon我認爲你的意思是你需要2個查詢而不是n + 1。因爲一個是笛卡爾產品,你說你不想要:-) – KLE 2009-10-12 14:07:45

+0

「......實體是對象,不是他們......」 - 不一定。對象和表之間不需要有1:1映射。 – duffymo 2009-10-12 14:11:22