2009-10-07 97 views
2

我有3個非抽象的持久化類。 MyClubUser和HisClubUser類繼承自User類。對於這些類,我使用每個子類策略的一個表,即@Inheritance(strategy = InheritanceType.JOINED)Hibernate繼承策略和爲什麼

我觀察到的是,當我在用戶類上進行查詢時,生成的SQL使用左外連接HisClubUser和MyClubUser。爲什麼Hibernate會這樣做[加入其他表]我只關心用戶的問題?我的觀點是,即使數據被檢索到,但如果返回了User實例,我將無法訪問MyClubUser或HisClubUser中的這些屬性。此外,這是否會導致額外的開銷,而不是隻查詢用戶表而沒有左外連接的查詢?

謝謝

回答

5

休眠總是返回實際類型的持久實體。如果您存儲了「MyClubUser」,它將作爲「MyClubUser」返回,而不是「用戶」。原因很明顯 - 如果Hibernate將「MyClubUser」作爲「用戶」返回,並且您要再次堅持,則會失去「MyClubUser」中定義的所有其他屬性。

爲了做到這一點,Hibernate需要知道實際類型是什麼。對於InheritanceType.JOINED策略,唯一的辦法是在繼承層次結構中檢查全部表(在技術上,它是當前級別或低於當前級別的表以及當前樹分支中當前級別以上的所有表)。所以,如果你有這樣一個層次結構:

  Root 
     / \ 
     Node1 Node2 
    / \ 
    Node11 Node12 

和你想從根本選擇,Hibernate會做所有表外連接。如果您從Node1中選擇,Hibernate將在Node1和Root上進行內連接,並在Node11和Node12上執行外連接。 Node2不會被觸及,因爲它不是Node1的後代。

就外連接開銷而言 - 是的,肯定有一個開銷,但這是您爲加入策略付出的代價。你可以使用鑑別器來避免這種情況,但是它帶有自己的副作用。這種開銷是否顯着取決於層次結構的深度和分佈,索引以及其他許多事情。聆聽KLE的建議並描述它。

+0

+1非常感謝這些細節,他們明確了爲什麼我的原始SimpleUser提案不適用於InheritanceType.JOINED。我從答案中刪除了這部分內容,而不是誤導任何人。 – KLE 2009-10-08 09:41:43

2

你在User上查詢,所以Hibernate會執行一個'多態查詢'。由於MyClubUser和HisClubUser本質上是User對象(它們繼承自User),因此Hibernate也會檢索這些類型的用戶。

4

爲什麼Hibernate會這樣[加入其他表]我關注的只是用戶?

因爲所有HisClubUser也是用戶的有效的情況下,這是合乎邏輯的,當你問用戶檢索這些。

我的觀點是,即使數據被檢索到,但我無法在MyClubUser或HisClubUser中訪問這些屬性,因爲返回了User實例。

你確定嗎?檢查(例如在調試中)返回的有效類,它應該是子類。因此可以進行向下轉換,並且可以訪問這些屬性。

此外,這是否會導致額外開銷與查詢相比,它只是查詢沒有左外連接的用戶表?

是的,額外的連接有開銷。這可能很重要或不重要:我建議你在你的具體情況下進行測試。

+1

+1。但是,您應該刪除SimpleUser的建議,因爲它不會幫助;我在我的回答中解釋了「爲什麼」。 – ChssPly76 2009-10-07 17:27:26

+0

@ ChssPly76謝謝。我已閱讀你的答案,現在我明白了「爲什麼」。你是對的:-) – KLE 2009-10-08 09:39:23

+0

謝謝你們......我現在明白了。我現在正在做的是MyClubUser和HisClubUser將與用戶建立1對1的關係,而不是從用戶繼承。要訪問MyClubUSer和HisClubUser中的其他屬性,我會再次查詢。用戶用於登錄。大多數時候使用特定的類。偶爾會讀取用戶中的屬性。 @KLE我相信。查詢只返回用戶,這是有道理的。如果可以下載,那麼用戶必須繼承MyClubUser和HisClubUser,這是不可能的。 – thlim 2009-10-10 04:50:11