三种继承关系映射:
subclass:只有一张表,此表有一个辨别者字段,用来分别每一条记录是父类,还是子类,同时子类的字段属性不允许为空
joined-subclass:有两张表,父类一张表,拥有父类的所有属性对应的字段,子类一张表,拥有子类独有的属性对应的字段,没有继承下来的父类的属性对应的字段,子类表的主键同时外键引用父类表的主键,当插入一个子类记录时,同时向父类表和子类表插入记录
union-subclass:有两张表,父类一张表,拥有父类的所有属性对应的字段,子类一张表,拥有子类的所有属性对应的字段以及继承父类的所有属性对应的字段,当插入一个子类记录时,只向子类那张表插入记录
首先是两个实体Bean, Person类与子类Student
Person类
//人
public class Person {
//主键ID
private Integer id;
private String name;
private int age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Student类
//学生
public class Student extends Person{
//学生独有的字段
private String school;
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
}
下面是三种继承关系映射
subclass
Person的XML配置文件:Person.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<!--
注意:记录类型是Person类型或是Student类型由辨别者列的字段值决定
1:在<class>节点中配置discriminator-value="person"属性,
说明名此记录为person类型
2:在<subclass>节点中配置discriminator-value="student"属性,
说明名此记录为student类型
-->
<hibernate-mapping package="entity6">
<!-- discriminator-value="person" : 插入Person记录时,
辨别者列的字段值为person
-->
<class name="Person" table="persons" discriminator-value="person">
<id name="id" type="java.lang.Integer">
<!-- name:表中的序列名 -->
<column name="id" />
<!-- 指定主键的生成方式,native:使用数据库本地的方式 -->
<generator class="native" />
</id>
<!-- 配置辨别者列 -->
<discriminator column="type" type="string"></discriminator>
<property name="name" type="java.lang.String">
<column name="name" />
</property>
<property name="age" type="int">
<column name="age" />
</property>
<!-- 映射Student子类 -->
<!-- discriminator-value="student" : 插入Person记录时,
辨别者列的字段值为student
-->
<subclass name="Student" discriminator-value="student">
<property name="school" type="string" column="school"></property>
</subclass>
</class>
</hibernate-mapping>
下面是HibernateTest测试
/**
* subclass缺点:
* 1. 使用了辨别者列
* 2. 子类独有的字段不能添加非空约束
* 3. 若继承层次比较深的话,则数据表的字段也比较多
*/
//增
@Test
public void test1(){
/**
* 插入操作:
* 1. 对于子类对象只需把记录插入到一张数据表中
* 2. 辨别者列由Hibernate自动维护,不需要人为插入该字段值
*/
//一条Person记录
Person person = new Person();
person.setName("person");
person.setAge(20);
//一条Student记录
Student student = new Student();
student.setName("student");
student.setAge(22);
student.setSchool("school");
//保存
session.save(person);
session.save(student);
}
//查
@Test
public void test2(){
/**
* 1. 查询父类记录,只需查询一张表
* 2 .查询子类记录,只需查询一张表
*/
//查询条件中"FROM Person" - Person不是表名,是类名!
List<Person> persons = session.createQuery("FROM Person").list();
System.out.println(persons.size());
//查询条件中"FROM Student" - Student不是表名,是类名!
List<Student> students = session.createQuery("FROM Student").list();
System.out.println(students.size());
}
joined-subclass
Person的XML配置文件:Person.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="entity7">
<class name="Person" table="persons">
<id name="id" type="java.lang.Integer">
<!-- name:表中的序列名 -->
<column name="id" />
<!-- 指定主键的生成方式,native:使用数据库本地的方式 -->
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="name" />
</property>
<property name="age" type="int">
<column name="age" />
</property>
<!-- 新建一张表存放子类 table="students" 表名:students -->
<joined-subclass name="Student" table="students">
<!--
key :此表的主键ID,同时外键引用Person的主键ID
column="" : 字段名
-->
<key column="student_id"></key>
<property name="school" type="string" column="school"></property>
</joined-subclass>
</class>
</hibernate-mapping>
下面是HibernateTest测试
/**
* joined-subclass优点:
* 1. 不需要使用了辨别者列
* 2. 子类独有的字段能添加非空约束
* 3. 没有冗余的字段
*/
//增
@Test
public void test1(){
/**
* 插入操作:
* 1. 对于子类对象需要插入到两张表中
*/
//一条Person记录
Person person = new Person();
person.setName("person");
person.setAge(20);
//一条Student记录
Student student = new Student();
student.setName("student");
student.setAge(22);
student.setSchool("school");
//保存
session.save(person);
session.save(student);
}
//查
@Test
public void test2(){
/**
* 1. 查询父类记录,做一个左外连接查询
* 2 .查询子类记录,做一个内连接查询
*/
//查询条件中"FROM Person" - Person不是表名,是类名!
List<Person> persons = session.createQuery("FROM Person").list();
System.out.println(persons.size());
//查询条件中"FROM Student" - Student不是表名,是类名!
List<Student> students = session.createQuery("FROM Student").list();
System.out.println(students.size());
}
union-subclass
Person的XML配置文件:Person.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="entity8">
<class name="Person" table="persons">
<id name="id" type="java.lang.Integer">
<!-- name:表中的序列名 -->
<column name="id" />
<!-- 主键的生成方式 不能使用native -->
<generator class="hilo" />
</id>
<property name="name" type="java.lang.String">
<column name="name" />
</property>
<property name="age" type="int">
<column name="age" />
</property>
<!--
union-subclass继承关系映射:
1. 新建一张表,此表有Person的所有字段(主键除外)
2. 此表还有Student独有的字段
3. table="":新建表的表名
-->
<union-subclass name="Student" table="students">
<!--
Student类独有的字段生成
name="":Student类中的属性名
column="":数据表的字段名
type="":字段的数据类型
-->
<property name="school" column="school" type="string"></property>
</union-subclass>
</class>
</hibernate-mapping>
下面是HibernateTest测试
/**
* union-subclass
* 优点:
* 1. 不需要使用了辨别者列
* 2. 子类独有的字段能添加非空约束
*
* 缺点:
* 1. 存在冗余的字段
* 2. 若更新父表的字段,更新效率较低
*/
//增
@Test
public void test1(){
/**
* 插入操作:
* 1. 对于子类对象只需要插入到一张表中
*/
//一条Person记录
Person person = new Person();
person.setName("person");
person.setAge(20);
//一条Student记录
Student student = new Student();
student.setName("student");
student.setAge(22);
student.setSchool("school");
//保存
session.save(person);
session.save(student);
}
//查
@Test
public void test2(){
/**
* 1. 查询父类记录,需把父表和子表记录汇总到一起再做查询,性能稍差
* 2. 查询子类记录,做一个内连接查询
*/
//查询条件中"FROM Person" - Person不是表名,是类名!
List<Person> persons = session.createQuery("FROM Person").list();
System.out.println(persons.size());
//查询条件中"FROM Student" - Student不是表名,是类名!
List<Student> students = session.createQuery("FROM Student").list();
System.out.println(students.size());
}
@Test
public void test3(){
/**
* "UPDATE Person":
* 1. Person是实体类名,不是数据表名
* 2. 更新时,只要跟Person有继承关系的子类,都会进行update age字段
*/
String sql = "UPDATE Person p SET p.age= 20";
session.createQuery(sql).executeUpdate();
}