8

我们对 PostgreSQL 中的继承以及将其映射为 JPA 中的实体有疑问。我们的数据库和我们要映射的表是:

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 

所以只是extends,但它不能正常工作。最好的方法是什么?提前致谢。

4

3 回答 3

8

JPA 的继承概念是基于普通表的。它并没有真正“理解”PostgreSQL 表继承的概念。这是使用旨在公开功能的最低公分母并且可移植的规范的成本之一。

有关JPA 继承策略的完整摘要,请参阅本指南。请注意,在较新的 Java 6 JavaDoc for @Inheritance中有一条注释说:

如果未指定 Inheritance 注释或未为实体类层次结构指定继承类型,则使用 SINGLE_TABLE 映射策略。

......如果你看看它是如何SINGLE_TABLE工作的,它对你不起作用也就不足为奇了;它期望所有子类都在一个具有魔术鉴别器值的大表中。

InheritanceType.TABLE_PER_CLASS更接近 Pg 的行为方式,但我怀疑当基本类型表具有叶类型的每个实体的条目时,JPA impl 会有点混乱。在查询超类时,它会尝试UNION跨子类表进行查询,这可能会产生奇怪的结果——如果使用的话至少会出现重复,如果UNION使用UNION ALL. 根据提供者如何实施策略,它可能至少部分起作用。您必须进行测试,结果可能是相当特定于提供商的。

对 JPA 的 PG 继承支持的一个非常好的实现可能需要 JPA 提供者扩展来实现新的继承策略,该策略理解 PostgreSQL 扩展的继承和ONLY查询。

如果您可以说服您的 JPA 实现SELECT ... FROM ONLY subclass_tableInheritanceType.TABLE_PER_CLASS模式下使用,那么它应该可以与 PostgreSQL 继承互操作。它只会看到每个表中的非继承行,并像处理普通表一样使用它们。然后,您的其他非 JPA 代码可以继续使用继承功能。我想您可以修改 Hibernate 的 PostgreSQL 方言代码来执行此操作,但我个人不会去那里,除非我绝对必须让 JPA 支持严重依赖继承的现有 PostgreSQL 模式。

于 2012-08-07T08:41:01.310 回答
3

有一个使用 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;
}
于 2015-11-03T02:09:02.553 回答
2

Hibernate 中的继承与 PostgreSQL 继承无关,尽管两者都试图完成相同的任务并且可能看起来相同。

其原因在于 Hibernate 以 SQL 标准为基础,从每个 RDBMS 中调整小的特定特性。例如,虽然 MySQL 对顺序 ID 有“自动增量”,但 Oracle 使用序列。

从历史上看,数据继承(或专业化)是通过对特定字段使用单独的表来完成的,主外键将这些表链接在一起。在您的示例中,MatchAnswer 的 ID 为 PK 和 FK 到 Answer.idAnswer。与 TrueFalseAnswer 相同(ID 是 Answer.idAnswer 的 PK/FK)。

您发布的“继承”定义不是(AFAIK)在任何 SQL 标准中定义的,因此,如果 Hibernate 支持这一点,我会感到惊讶,特别是因为它似乎是 PostgreSQL 特有的东西,而且它似乎是一个有点实验性的特性:查看 PostgreSQL 文档“继承”一章的“注意事项”。

也就是说,我建议保持您的数据健全,根据最佳关系模型实践映射它们。然后,在您的 Hibernate 映射中,您可以在有意义的地方表达数据继承。

于 2012-08-07T08:39:48.927 回答