【问题标题】:Correct database design for JPA entity inheritanceJPA 实体继承的正确数据库设计
【发布时间】:2013-12-06 14:28:45
【问题描述】:

我正在开始一个使用 JPA 2 + Hibernate 4.2.6 进行数据访问的新项目。

我的数据库中有两个表代表两种不同的Answer,所以我有answer_type_aanswer_type_b 表。 除了一个字段之外,它们是相同的。

现在我正在创建我的模型类,我想从通用超类或接口 Answer 继承我的 AnswerAAnswerB 实体。

我阅读了一些关于实体继承的文档:

但我对如何构建我的数据库和我的实体类来实现这一点没有清晰的认识。你能帮帮我吗?

【问题讨论】:

  • 您使用的是哪个版本的 JPA 和 Hibernate?
  • @PaulVargas 更新了我的问题

标签: java hibernate inheritance jpa


【解决方案1】:

您需要表格Answer - 对于特定的其他人来说是超级的,您应该在其中放置answer_type_aanswer_type_b 的所有常用列。假设Answer.a_id 是主键,那么answer_type_a.a_id answer_type_b.a_id 同时是主键和外键。

当然不要忘记将区分列放置到answer_type_aanswer_type_b

+---------+
| Answer  |
+---------+       ----------------------->--+--------------+
| a_id    +------)                          | answer_type_b|
                  ---->-+--------------+    +--------------+ 
  ...                   | answer_type_a|    | a_id         |
                        +--------------+       ...
                        | a_id         |
                           ....

【讨论】:

  • 为什么我应该更喜欢这种方法而不是创建@MappedSuperclass 类(避免在我的数据库中创建新表)?
  • 这在很大程度上取决于answer_type_aanswer_type_b 中的信息量,假设那里有很大的区别 - 然后为了减少表开销,您需要单独的表。否则使用 MapperSuperclass 或审查鉴别器的可能性 (openjpa.apache.org/builds/1.2.3/apache-openjpa/docs/…)
【解决方案2】:

您需要使用公共字段创建一个名为Answer 的类,并使用@MappedSuperclass 对其进行注释。此外,您将拥有 2 个实体类,名为 AnswerAAnswerB,它们仅包含“额外”字段。

如果你有2个表,那么你需要使用TABLE_PER_CLASS继承类型。所以将@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) 添加到Answer 类中,并可能在AnswerAAnswerB 中添加@Table 注释。

但如果我是你,我会为所有答案使用一个表格,其中包含所有需要的列 + 一个鉴别器列,这样你就可以区分一行是答案类型 a 还是类型 b。

【讨论】:

    【解决方案3】:

    嗯,据我了解,您的问题是关于映射的:

    你需要一个 java 类 Answer 这实际上是你的超类。由于没有对应的数据库表,所以必须标注@MappedSuperclass

    @MappedSuperclass
    public class Answer {
    //fields&properties
    }
    

    现在两个类来了,它们是实体,因为它们被持久化在数据库表中:

    @Entity
    @Table("answer_type_a")
    public class AnswerA extends Answer {
      //here you add the field that is not common with AnswerB
    }
    @Entity
    @Table("answer_type_b")
    public class AnswerB extends Answer {
      //here you add the field that is not common with AnswerA
    }
    

    PS:恕我直言,您不需要任何继承注释,因为映射的超类不是实体。

    【讨论】:

      【解决方案4】:

      我最近也遇到了和你类似的情况。找到的最佳解决方案是使用抽象类作为超类型,并将该类扩展到具体类型(它将代表您的实体)。

      因此,对于您的情况,您可以像这样建模。

      @MappedSuperClass
      public abstract class Answer{
          @Id 
          @GeneratedValue(strategy=GenerationType.IDENTITY)
          public Integer id;
      
          @Column
          String commonFieldOne;
      
          @Column
          String commonFieldTwo;
      
          @Column
          String commonFieldThree;    
          ...    
      }
      

      请注意,我使用了@MappedSuperClass 注释。这告诉 JPA 这是一个不会被实例化的超类,并且不应该有与之关联的数据库表。 另请注意,将作为两个子表的主键的Id 是在此类中定义的

      现在对于您的具体类(将映射到您数据库中的表),您将使用 @Entity 注释。

      @Entity
      @Table("answer_type_a")
      public class AnswerA extends Answer{
         //All common fields from Answer table will be included in the DB tables as columns automatically
      
          @Column
          String uniqueFieldOne;
          ....
      
      }
      

      你可以对@Table("answer_type_b")做同样的事情

      希望这会有所帮助!

      【讨论】:

        【解决方案5】:

        只需在您的数据库中创建一个表,例如包含两个字段的答案。您必须具有三个类,第 1 类:答案,第 2 类:Answer_Type_A 扩展答案,第 3 类:Answer_Type_B 扩展答案。 Answer(超类)将有一个 hbm 文件,每个 Answer_Type_A 和 Answer_Type_B 将有两个 hbm。在 sybclass 中的 hbm 文件包括:

        <hibernate-mapping>  <subclass name="com.test.Answer_Type_A" 
            extends="com.test.Answer">
        <property name="fieldA" />
        </subclass>
        </hibernate-mapping>
        

        【讨论】:

          猜你喜欢
          • 2015-05-29
          • 2015-05-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-11-19
          • 2015-08-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多