2010-06-23 68 views
4

我的數據庫有兩個表,「問題」和「字段」。問題可能有很多領域,而領域可能有很多領域。它是一個具有特殊根節點的樹。休眠,SQL和遞歸關聯

我想用它們與hibernate(目前potgresql) - 所以它應該是簡單易用的使用它從Java。

這是最好的解決方案是什麼?

  1. 將question_parent_id和field_parent_id添加到「字段」表中,並且只有在它是它的直接後代時才使用question_parent_id。 (檢查異或SQL約束...可能依賴於SQL服務器)
  2. 添加question_parent_id和field_parent_id,並始終使用question_parent_id。記住要保持一致...(question_id不應該改變,可能不是真正的風險)
  3. 使用postgresql特定的表繼承:「question」和「field」擴展了「content」,所以一個外鍵列就足夠了。對「問題」和「字段」使用額外的限制。
  4. 使用第三個表(稱爲「容器」),只包含一個id。容器可能有很多領域,並且一個領域可能有一個容器。問題可能存在一個容器。但是這需要在Java中的額外代碼,並具有無限循環的風險,即使在field_container_id的唯一鍵...
+0

我在回答中添加了更多段落。你需要提供一些更具體的信息來獲得具體的答案。 (想想問一個新的問題,如果你發現一些特定的要求。) – 2010-07-06 23:08:13

回答

2

我寧願考慮類模型而不是關於關係模型。最終用戶通常不會關心數據庫中有多少個密鑰。他正在使用你的課程,它應該是「簡單易用」的。所以先寫你的班級模型,然後再考慮映射。

數據庫中的解決方案取決於您的類模型。

編輯:你的模型在另一邊取決於你需要做什麼。

導航:你通常需要一個問題的所有領域?你通常只需要直接分配給問題或字段的字段,還是隻需遞歸地在樹上的所有字段?你需要了解一個領域的父母嗎?等等。

查詢:您是否需要按指定給他們的字段過濾問題或字段?遞歸?你需要父母過濾字段嗎?等等。

換句話說:你無法對所有的東西進行優化。有典型的查詢和典型的導航路徑。支持太多的方法可能會變得昂貴,並且可能需要模型和數據庫中的冗餘數據,這使得難以維護。

+0

+1作爲終端用戶尊重客戶代碼以推出最佳設計。 :) – 2010-07-05 16:42:31

0

除非我失去了一些東西,你有[Question]之間的一個一對多的關係和[Field](這是一對多的,對嗎?)和一個自引用[Field]之間的一對多關聯。因此,我想:

  • 添加question_id[Field]表前者關係
  • 添加parent_id到了[Field]表爲後來的關係

Hibernate可以沒有任何問題映射此。

+0

是的,這是我的#1或#2 :) – Dutow 2010-06-23 14:42:41

+0

@Dutow是的,但我無法發現差異(這一定是顯而易見的:) – 2010-06-23 14:46:44

+0

in#1:question.fields [x] .question_id!= NULL && question.fields [x] .fields [y] .question_id == NULL對於每個x和y,總是如此。 in#2 question.fields [x] .question_id!= NULL && question.fields [x] .fields [y] .question_id!= NULL對於每個x和y,總是爲真。 (#2可以是incosistent:fields [x] .fields [y] .parent_id!= fields [x] .parent_id) – Dutow 2010-06-23 15:33:29

0

如果你想要一個高性能的解決方案,你必須仔細考慮你的層次結構會有多深。這種類型的遞歸結構對於休眠加載來說可能是非常昂貴的,因爲它通常會最終爲每個字段創建大量聯接,因爲它可能有子字段(並且它們可能具有子字段等等)

如果你想允許無限的深度,但你總是想加載整個問題,包括所有的領域和子領域。然後我會建議Field有一個父字段(可爲空)和一個擁有問題(不可爲空)。這使您可以使用以下HQL高效地加載整個問題:

SELECT q FROM Question q 
JOIN FETCH q.allFields