初识Hibernate之继承映射

作者: Single_YAM | 来源:发表于2017-10-16 16:55 被阅读17次

         前面的两篇文章中,我们介绍了两张表之间的各种相互关联映射关系,但往往我们也会遇到两张表甚至多张表之间共有着多个相同的字段。例如:

    这里写图片描述

    如图,student表和teacher表共同具有id,name,age等字段,而我们的继承映射就是这样的一个思想,抽象出这些共有的字段为一张父表,让子表对其进行继承,这样就可以大大降低我们实体类代码的冗余性,增强其结构的完善。

    这里写图片描述

    Hibernate支持以下三种数据表的生成策略:

    • 每个类分层结构一张表
    • 每个子类一张表
    • 每个具体类一张表

    一、每个类分层结构一张表
         对于这种数据表的生成策略,最终Hibernate会在数据库中生成一张数据表,这张数据表的结构会是如下的:

    这里写图片描述

    无论你是student记录还是teacher记录,都会被存储到这张集成的新表中。下面是实现代码:

    public class Person {
        private int id;
        private String name;
        //省略get,set方法
    }
    
    public class Student extends Person {
        private int grade;
        //省略get,set方法
    }
    
    public class Teacher extends Person {
        private int salary;
        //省略get,set方法
    }
    

    下面是映射配置文件的书写:

    <class name="Person" abstract="true" table="newTable">
        <id name="id">
            <generator class="assigned"/>
        </id>
        <!--指定鉴别器列的名称和类型-->
        <discriminator column="type" type="java.lang.String"/>
        <property name="name"/>
        <!--指定集成到新表的子实体类-->
        <subclass name="Student" discriminator-value="stu">
            <!--配置继承类中其他属性-->
            <property name="grade"/>
        </subclass>
        <subclass name="Teacher" discriminator-value="tea">
            <property name="salary"/>
        </subclass>
    </class>
    

    abstract="true"指定Hibernate不用将Person表生成具体表,只需要生成一张集成的新表即可。table="newTable"则指定了新表的表名,鉴别器就是用来区分当前记录时student或是teacher的一个标记,它会在新表中生成一个字段,而该字段的名称和类型都在此处进行指定。

    subclass标签用于配置需要集成到新表中子实体类的一些属性等内容。下面我们通过插入操作了解这种映射策略对具体数据库的实际操作。

    Student student = new Student();
    student.setId(1);
    student.setName("stu1");
    student.setGrade(100);
    
    Teacher teacher  = new Teacher();
    teacher.setId(2);
    teacher.setName("tea1");
    teacher.setSalary(10000);
    
    session.save(student);
    session.save(teacher);
    

    将两条不同类型的记录保存到数据库中,

    这里写图片描述

    newTable是一张综合的表,主要由student表和teacher表集成而来,对应于student表的记录salary字段的值为空,对应于teacher表记录的grade字段值为空。那在我们取数据的时候,Hibernate该如何区分当前记录对应的是哪个实体类的呢?

    Person person = (Person)session.get(Person.class,1);
    if(person instanceof Student){
        Student student1 = (Student)person;
        System.out.println("i am student,my grade is:"+student1.getGrade());
    }
    

    实际上,Hibernate使用多态来对数据记录进行接收,无论你是Student记录或teacher记录,都可以被person类型接收。使用这种策略方式映射数据表只会生成一张表,但是很大的一个问题是,当很多张表进行集成的时候会导致表结构复杂混乱。

    二、每个具体类映射成一张表
         这种数据表的生成策略会为每个实体类生成一张数据表,就上述例子而言,会为person,student,teacher都生成一张表。首先我们看映射配置文件:

    <class name="Person">
        <id name="id">
            <generator class="assigned"/>
        </id>
        <property name="name"/>
        <union-subclass name="Student" table="students">
            <property name="grade"/>
        </union-subclass>
        <union-subclass name="Teacher" table="teachers">
            <property name="salary"/>
        </union-subclass>
    </class>
    

    这里的配置其实不需要多的解释,union-subclass告诉Hibernate当前配置的实体类是person类的子类,并用table属性指定对应数据库的表名。下面我们通过插入数据来看看具体生成的表的结构:

    这里写图片描述

    很明显,我们的person表只起到一个模板的效果并没有什么实际的价值,而我们students表和teachers表的id,name字段都是从person表中继承得到的。

    三、每个子类一张表
         这种数据表的生成策略的主要思想就是将公共的信息存放在父表中,子表只保存自己独有的字段信息了。例如:

    <class name="Person">
        <id name="id" column="id">
           <generator class="native"/>
        </id>
        <property name="name"/>
        <joined-subclass name="Student" table="students">
            <key column="sId" />
            <property name="grade"/>
        </joined-subclass>
        <joined-subclass name="Teacher" table="teachers">
            <key column="tId"/>
            <property name="salary"/>
        </joined-subclass>
    </class>
    

    我们使用 joined-subclass来配置继承子类,在Hibernate生成数据表的时候会将student和teacher表的主键作为外键关联父表的主键。下面是插入数据:

    Student student = new Student();
    student.setName("stu1");
    student.setGrade(12);
    
    Teacher teacher = new Teacher();
    teacher.setName("tea1");
    teacher.setSalary(1233);
    
    session.save(student);
    session.save(teacher);
    
    这里写图片描述

    显然,我们student或者teacher表不再需要存放name或者其他共有字段的信息,只需要通过自己的主键去查找父表即可得到。

    至此,有关继承映射的三个策略已经介绍结束,总结不到之处,望指出。

    相关文章

      网友评论

        本文标题:初识Hibernate之继承映射

        本文链接:https://www.haomeiwen.com/subject/jcqluxtx.html