0
点赞
收藏
分享

微信扫一扫

Hibernate继承映射

MaxWen 2021-09-21 阅读 23

继承映射

对于面向对象的程序设计语言而言,继承和多态是两个最基本的概念。Hibernate的继承映射可以理解为持久化类之间的继承关系。

Hibernate支持三种继承映射的策略:

  • subclass:将域模型中的每一个对象映射到一个独立的表中,也就是说不需要在关系型数据模型中考虑域模型的继承关系和多态。
  • joined-subclass:对于继承关系中的子类使用同一个表,这需要在数据表中添加额外的属性区分子类类型的字段。
  • union-subclass:域模型中的每个类映射到一个表中。通过关系数据模型中的外键来描述表之间的继承关系。相当于按照域模型中的结构建立数据库中的表,并通过外键建立表之间的继承关系。

使用subclass元素进行继承映射

使用subclass的继承映射可以实现继承关系中的父类和子类使用同一张表。

因为父类和子类保存在同一张表中,因此需要在表中添加额外的一列,使用该列来区分每行记录到底是哪个类的实例,这个列被称作辨别者列(discriminator)。

在这种映射策略下,使用subclass来映射子类,使用class或subclass的discriminator-value属性指定辨别者列的值。

所有子类定义的字段都不能有非空约束。如果为那些字段添加非空约束,那么父类实例在那些列中实际上并没有值,这将引起数据库完整性的冲突,导致父类实例无法保存到数据库中。

示例:

创建Person类(父类)

public class Person {
    private Integer id;
    private String name;
    private int age;

    //Getter and setter
}

创建Student类(子类)

public class Student extends Person {
    private String school;

    //Getter and setter
}

配置文件(Person.hbm.xml)

<hibernate-mapping package="com.hibernate.subclass">
    <class name="Person" table="person" discriminator-value="PERSON">
        <id name="id" type="java.lang.Integer">
            <column name="ID"/>
            <generator class="native"/>
        </id>
        <discriminator column="TYPE" type="java.lang.String"></discriminator>
        <property name="name" type="java.lang.String">
            <column name="NAME"/>
        </property>
        <subclass name="Student" discriminator-value="STUDENT">
            <property name="school" type="java.lang.String" column="SCHOOL"></property>
        </subclass>
    </class>
</hibernate-mapping>

测试类

Person person = new Person();
person.setName("person1");
person.setAge(11);

session.save(person);

Student student = new Student();
student.setName("person2");
student.setAge(12);
student.setSchool("School1");
session.save(student);

对于子类对象只需要把记录插入到数据表中。辨别者列由Hibernate自动维护。

执行查询操作

List<Person>persons = session.createQuery("from Person").list();
System.out.println(persons.size());

查询父类记录只需要查询一张数据表。
对于子类记录,也只需要查询一张数据表。

缺点:

  1. 使用了辨别者列。
  2. 子类独有的字段不能添加非空约束。
  3. 如果继承的层次很深,会导致数据表的字段增多。

使用joined-subclass元素进行继承映射

采用joined-subclass元素继承的映射可以实现每个子类一张表。

采用这个映射策略时,父类实例保存在父类表中,子类实例由父类表和子类表共同存储,因为子类实例也是一种特殊的父类实例,因此也必然包括父类实例的属性,于是将子类和父类的共同属性保存在父类表中,子类增加属性,则保存在子类表中。

在这种映射策略下,无须使用辨别者列,但需要为每个子类使用key元素映射共有主键。

子类增加的属性可以添加非空约束。因为子类的属性和父类的属性没有保存在同一张表中。

示例

依然使用之前的类,只是Person.hbm.xml文件需要更改

<hibernate-mapping package="com.hibernate.joinedsubclass">
<class name="Person" table="person">
    <id name="id" type="java.lang.Integer">
        <column name="ID"/>
        <generator class="native"/>
    </id>
    <discriminator column="TYPE" type="java.lang.String"></discriminator>
    <property name="name" type="java.lang.String">
        <column name="NAME"/>
    </property>
    <joined-subclass name="Student" table="student">
        <key column="student_id"></key>
        <property name="school" type="java.lang.String" column="SCHOOL"></property>
    </joined-subclass>
</class>
</hibernate-mapping>

joined-subclass的优点:

  1. 不需要使用辨别者列。
  2. 子类的字段可以添加非空约束。
  3. 没有冗余的字段。

joined-subclass的缺点:
插入操作:
和subclass不同,joinedsubclass至少要插入到两张数据表中。
查询操作:

  1. 查询父类记录,做一个左外连接查询。
  2. 对于子类记录,做一个内连接查询。

采用union-subclass进行继承映射

采用union-subclass元素可以实现将每一个实体类对象映射到一个独立的表中。

子类增加的属性可以有非空约束,即父类实例的数据保存在父表中,而子类实例的数据保存在子类表中。

子类实例的数据仅保存在子类表中,而在父类表中没有任何记录。
在这种映射策略下,子类表的字段会比父类表的字段要多,因为子类表的字段等于父类表的字段,加子类表新增的字段的总和。

在这种映射策略下,既不需要使用辨别者列,也不使用key元素映射共同的主键。

使用union-subclass的映射策略是无法使用identity的主键生成策略。因为同一类继承层次中所有实体类都要使用同一个主键种子。即多个持久化实体对应的记录的主键应该是连续的,受此影响,也不应该使用native的主键生成策略。因为native会根据数据库使用identity或者sequence。

同样只需要修改Person.hbm.xml即可

<hibernate-mapping package="com.hibernate.unionsubclass">
<class name="Person" table="person">
    <id name="id" type="java.lang.Integer">
        <column name="ID"/>
        <generator class="native"/>
    </id>
    <property name="name" type="java.lang.String">
        <column name="NAME"/>
    </property>
    <union-subclass name="Student" table="student">
        <property name="school" type="java.lang.String" column="SCHOOL"></property>
    </union-subclass>
</class>
</hibernate-mapping>

union-subclass的优点:

  1. 无需使用辨别者列。
  2. 子类的字段可以添加非空约束。
  3. 对于子查询只需要查询一张表。

union-subclass的缺点:

  1. 存在冗余的字段。
  2. 查询父类的性能偏弱,因为需要有子查询,将父表和子表的记录汇聚到一起。
  3. 若更新父表的字段,则更新的效率较低。
举报

相关推荐

0 条评论