2012-08-07 73 views
4

我們對PostgreSQL中的繼承存在疑問,並將它映射爲JPA中的實體。 我們的數據庫和表我們要地圖是:PostgreSQL與JPA繼承,Hibernate

CREATE TABLE Answer (
    idAnswer SERIAL, 
    answerContent VARCHAR, 
    idQuestion INTEGER, 
    version INTEGER, 

    CONSTRAINT Answer_idAnswer_PK PRIMARY KEY (idAnswer), 
    CONSTRAINT Answer_idQuestion_FK FOREIGN KEY (idQuestion) REFERENCES Question(idQuestion) 
); 


CREATE TABLE MatchAnswer (
    matchingAnswer VARCHAR NOT NULL, 
    version INTEGER, 

    CONSTRAINT MatchAnswer_idAnswer_PK PRIMARY KEY (idAnswer)  
) INHERITS(Answer); 


CREATE TABLE TrueFalseAnswer (
    isTrue BOOLEAN NOT NULL, 
    version INTEGER, 

    CONSTRAINT TrueFalseAnswer_idAnswer_PK PRIMARY KEY (idAnswer) 
) INHERITS(Answer); 

我們映射他們在Netbeans的7.1.2使用自動工具實體。 起初,我認爲這將是足夠的只是添加

@Entity 
@Table(name = "truefalseanswer", catalog = "jobfairdb", schema = "public") 
@XmlRootElement 
public class Truefalseanswer extends Answer implements Serializable { 
    private static final 

所以只是延伸,但它並沒有正常工作。 這是最好的方法是什麼?提前致謝。

+0

您正在使用哪個PostgreSQL版本?有助於說,因爲不同的版本有不同的功能。 – 2012-08-07 08:33:27

+0

PostgreSQL 9.1.4,但我們決定簡化這個想法。 – Atais 2012-08-07 09:27:18

回答

6

JPA的繼承概念是基於普通表。它並不真正「獲得」PostgreSQL表的繼承。這是使用旨在揭示功能的最低公分母的規範工作的成本之一,並且可移植性很高。

請參閱this guide瞭解JPA繼承策略的體面摘要。需要注意的是,在newer Java 6 JavaDoc for @Inheritance有一張紙條說:

如果沒有指定繼承的註釋,或者如果一個實體類層次結構中沒有指定繼承 類型,則使用SINGLE_TABLE 映射策略。

...如果你看看SINGLE_TABLE如何工作,這並不奇怪,它不適合你;它期望所有的子類都在一個具有魔術鑑別器值的大表中。

InheritanceType.TABLE_PER_CLASS更接近於Pg的行爲方式,但我懷疑當基類型表具有葉類型的每個實體的條目時,JPA impl會有點困惑。在查詢超類時,它會嘗試在子類表中執行類似UNION的查詢,這可能會產生奇怪的結果 - 如果使用UNION,則至少會出現重複,如果使用UNION ALL,則會出現性能問題。具體取決於提供者如何實施策略,它可能至少部分工作。你必須測試,並且結果可能與提供者相關。

爲PGA繼承支持JPA的一個非常好的實現可能需要JPA提供程序擴展爲一個新的繼承策略,該繼承策略可以理解PostgreSQL擴展的繼承和ONLY查詢。

如果您可以在InheritanceType.TABLE_PER_CLASS模式下說服您的JPA實現使用SELECT ... FROM ONLY subclass_table,那麼它應該與PostgreSQL繼承互操作。它只會看到每個表中的非繼承行,並像它們是普通表一樣工作。您的其他非JPA代碼可以繼續使用繼承功能。我想可能你可以修改Hibernate的PostgreSQL方言代碼來做到這一點,但我個人不會去那裏,除非我絕對讓JPA支持依賴於繼承的現有PostgreSQL模式。

+0

好吧,說實際上給了我們一個我們試圖實現的東西的視圖,所以我們決定通過重構表格來簡化這個想法...謝謝! – Atais 2012-08-07 09:29:05

1

Hibernate中的繼承與PostgreSQL繼承無關,儘管兩者都試圖完成相同的功能,並且看起來可能相同。

原因是Hibernate以SQL標準爲基礎,並調整每個RDBMS的小特性。例如,儘管MySQL對連續ID有「自動增量」,但Oracle使用序列。

從歷史上看,數據繼承(或專業化)已通過對特定字段使用單獨的表完成,主外鍵將這些表連接在一起。在你的例子中,MatchAnswer將ID作爲PK和FK給Answer.idAnswer。與TrueFalseAnswer相同(ID爲PK/FK至Answer.idAnswer)。

,您張貼不(據我所知)在任何SQL標準中定義的「繼承」的定義,所以,我會感到驚訝,如果休眠支持這一點,特別是因爲它似乎是非常具體到PostgreSQL 它的東西看起來這是一個有點實驗性的功能:查看PostgreSQL文檔「繼承」一章中的「注意事項」。

也就是說,我建議保持數據健全,根據最佳關係模型實踐對其進行映射。然後,在你的Hibernate映射中,你可以在有意義的地方表達數據繼承。

+0

這不是非常實驗性的,但它確實是一個有限的功能。我不會使用來自JPA的PostgreSQL繼承 - 或者除了奇數個例外,它都派上用場。它主要用於使表格分區對於應用程序來說是透明的,甚至存在一些奇怪的怪癖。 – 2012-08-07 08:47:40

2

有一個使用MappedSuperClass註解的解決方案。

@MappedSuperClass 
public abstract class AbstractAnswer{ 
    @Id 
    protected Long idAnswer; 

    @Column(name="answerContent") 
    protected String answerContent; 
} 

@Entity 
@Table(name="Answer") 
public class Answer extends AbstractAnswer{ 

} 

@Entity 
@Table(name="MatchAnswer") 
public class MatchAnswer extends AbstractAnswer{ 
    protected String matchingAnswer; 
} 

@Entity 
@Table(name="TrueFalseAnswer") 
public class TrueFalseAnswer extends AbstractAnswer{ 
    protected Boolean trueFalseAnswer; 
} 
+0

有一個限制,即父表不應該有任何外鍵本身。通過將這個字段分開放置在每個子類中,而不是保留在父類中,可以在Java級別解決這個問題。 – Piyush 2015-11-03 02:10:39

+0

我現在發現的這種方法存在問題。如果使用IDENTITY @Id,則子類將嘗試查找「subclass_id_seq」而不是「abstract_answer_id_seq」。如果不在每個子類中手動指定序列生成器名稱,我不知道如何解決這個問題。 – 2018-02-28 13:37:17