我們有與Hibernate 3.3 n + 1個選擇問題。休眠OneToOne自動連接抓取(分辨n + 1個問題)
爲了簡便起見,我只是做了簡短抽象的例子。
假設我們有以下簡單的類:
class MainEntity {
@Id
public Long id; //we have a table generator create this id
@OneToOne (mappedBy ="main")
public SubEntity subEntity;
}
class SubEntity {
@Id
@Column(name = "mainId") //note that this is the same column as the join column below
public Long mainId; //in order to have the exact same id as the corresponding MainEntity
@OneToOne (fetch = FetchType.LAZY)
@JoinColumn (name = "mainId", insertable = false, updatable = false, nullable = false)
public MainEntity main; //this is used for navigation and queries (" ... subentity.main = :x")
}
因此,大家可以看到SubEntity
有關係MainEntity
由兩個屬性,其中mainId
屬性是一個負責管理的關係表達/外鍵。
這工作得很好,完全符合我們的需求。
然而,有一個問題與MainEntity
一起熱切加載SubEntity
。
假設我有一個返回的MainEntity
集合的查詢。使用當前設置,Hibernate將發出n + 1個選擇:查詢本身+ n爲每個SubEntity
選擇一個。
當然,我可以添加一個join fetch
到查詢,但我寧願像Hibernate來自動做。因此我嘗試添加@Fetch(FetchMode.JOIN)
,但那沒有做任何事情。
我本來還使用@Fetch(FetchMode.SUBSELECT)
,應減少SELECT語句2沒問題 - 原來的查詢和子實體選擇(至少這是與@CollectionOfElements
和@Fetch(FetchMode.SUBSELECT)
註釋的另一個屬性會發生什麼)。
所以,問題是:我怎麼會告訴Hibernate來自動連接抓取或以熱切加載子實體使用一個選擇?我錯過了什麼嗎?
由於提前,
托馬斯
PS:有一兩件事,可能是一個問題可能是不引用實際的ID列mappedBy = "main"
,但我不能將其更改爲mappedBy = "id"
。
我不知道'@ MapsId',謝謝。我會嘗試一下。即使在n + 1問題不能解決的情況下,我仍然更喜歡這種方法來解決我們當前的問題。只是一個問題:這會讓我實際上只是設置ID而不參考MainEntity?我們有一些情況下缺少創建SubEntity實例,我們只有相應的MainEntity的id。如果可能的話,我寧願不必加載'MainEntity'來設置參考。換句話說:如果'id'有一個值,'mainEntity'是'null',會發生什麼? – Thomas
我只看了一下你鏈接到的'@ MapsId'文檔,不幸的是,這個註釋似乎是在Hibernate 3.5(和JPA 2)中引入的。然而,我們目前堅持使用JBoss 4.2.3(它不支持JPA 2),因此無法使用Hibernate 3.5(我們正在遷移到JBoss 6,但這需要一段時間)。 – Thomas
@Thomas回答你的第一條評論。如何用'MainEntity'的Id創建'SubEntity'。您需要使用'EntityManager.getReference'來獲取對「MainEntity」的引用,而不加載它並將其設置爲SubEntiy.main關係而不加載Main。 –