文章目录
实际上从容器映射开始就应进入了多表操作的时代,而继承映射也是多表,但是在继承映射的操作之中,关注的是表的继承于类继承的对应关系,在整个Hibernate里面一共支持有如下几种继承映射关系:
(1)UNION-CLASS:每一个继承子表对应一个实体类;
(2)SUBCLASS:每个类对应一张数据表,数据表中存在有继承关系;
(3)JOINED-SUBCLASS:连接子类策略,识别器。
1 继承形式一:UNION-CLASS
这种的继承关系重点只在于程序的维护上,而数据表上依然会存在有重复数据。
范例:数据库脚本
-- 删除数据表
DROP TABLE IF EXISTS student;
DROP TABLE IF EXISTS worker;
-- 创建数据表
CREATE TABLE student(
id VARCHAR(50),
name VARCHAR(50),
age INT,
sschool VARCHAR(50),
sscore DOUBLE,
CONSTRAINT pk_id1 PRIMARY KEY(id)
);
CREATE TABLE worker(
id VARCHAR(50),
name VARCHAR(50),
age INT,
wcompany VARCHAR(50),
wsalary DOUBLE,
CONSTRAINT pk_id2 PRIMARY KEY(id)
);
此时两张数据表的创建脚本完成,而后通过这个脚本可以分析出:id、name、age三个字段在两张表中被重复定义了。但是 如果按照传统的思路,现在应该准备出两个类:
1.1 基于*.hbm.xml
文件实现
在Hibernate最早的时期已经支持了这样的继承映射,所以可以直接使用*.hbm.xml
文件完成此类配置。
范例:定义一个Member.java的抽象类,设置公共属性信息
package org.lks.pojo;
import java.io.Serializable;
@SuppressWarnings("serial")
public abstract class Member implements Serializable {
private String id;
private String name;
private Integer age;
}
随后在Member类里面提供有公共的属性,那么Student或者是Worker子类就可以继承Member类。
范例:定义Student.java类
package org.lks.pojo;
@SuppressWarnings("serial")
public class Student extends Member implements java.io.Serializable {
private String sschool;
private Double sscore;
}
范例:定义Worker.java类
package org.lks.pojo;
@SuppressWarnings("serial")
public class Worker extends Member implements java.io.Serializable {
private String wcompany;
private Double wsalary;
}
从面向对象的角度来看,此时的代码已经符合于面向对象的设计要求了,重复的属性可以在子类中通过继承关系继续使用。
范例:随后的重点部分就要在映射文件的编写上了
(1)继承关系之中有一个重要的特点:所有子类对象都可以向父类对象转换,所以在进行操作的过程中对于映射文件只要求提供一个Member.hbm.xml文件即可。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.lks.pojo.Member" catalog="hedb">
<id name="id" type="java.lang.String">
<column name="id" length="50" />
<generator class="assigned"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name" length="50" />
</property>
<property name="age" type="java.lang.Integer">
<column name="age" />
</property>
<!-- 表示学生信息 -->
<union-subclass name="org.lks.pojo.Student" table="student" catalog="hedb">
<property name="sschool" type="java.lang.String">
<column name="sschool" length="50" />
</property>
<property name="sscore" type="java.lang.Double">
<column name="sscore" precision="22" scale="0" />
</property>
</union-subclass>
<!-- 表示工人信息 -->
<union-subclass name="org.lks.pojo.Worker" table="worker" catalog="hedb">
<property name="wcompany" type="java.lang.String">
<column name="wcompany" length="50" />
</property>
<property name="wsalary" type="java.lang.Double">
<column name="wsalary" precision="22" scale="0" />
</property>
</union-subclass>
</class>
</hibernate-mapping>
范例:测试学生增加
package org.lks.test;
import org.lks.dbc.HibernateSessionFactory;
import org.lks.pojo.Student;
public class TestMemberInsert {
public static void main(String[] args) {
Student stu = new Student();
stu.setId("stu - 1");
stu.setName("hhy");
stu.setAge(20);
stu.setSschool("xxx");
stu.setSscore(120.0);
System.out.println(HibernateSessionFactory.getSession().save(stu));
HibernateSessionFactory.getSession().beginTransaction().commit();
HibernateSessionFactory.closeSession();
System.exit(0);
}
}
stu - 1
Hibernate:
insert
into
hedb.student
(name, age, sschool, sscore, id)
values
(?, ?, ?, ?, ?)
现在如果保存的是学生信息(使用的是学生这个子类),那么SQL语句将向student表中保存。
范例:保存工人信息
package org.lks.test;
import org.lks.dbc.HibernateSessionFactory;
import org.lks.pojo.Worker;
public class TestWorkerInsert {
public static void main(String[] args) {
Worker worker = new Worker();
worker.setId("worker - 1");
worker.setName("lks");
worker.setAge(23);
worker.setWcompany("xxx");
worker.setWsalary(12000.0);
System.out.println(HibernateSessionFactory.getSession().save(worker));
HibernateSessionFactory.getSession().beginTransaction().commit();
HibernateSessionFactory.closeSession();
System.exit(0);
}
}
worker - 1
Hibernate:
insert
into
hedb.worker
(name, age, wcompany, wsalary, id)
values
(?, ?, ?, ?, ?)
此时发现在使用子类映射的过程之中,虽然只有一个映射的文件,但是会根据使用子类的不同找到不同的数据表进行操作。
范例:数据查询
package org.lks.test;
import org.lks.dbc.HibernateSessionFactory;
import org.lks.pojo.Student;
public class TestStudentGet {
public static void main(String[] args) {
Student stu = (Student) HibernateSessionFactory.getSession().get(Student.class, "stu - 1");
System.out.println(stu);
HibernateSessionFactory.closeSession();
System.exit(0);
}
}
Hibernate:
select
student0_.id as id1_0_0_,
student0_.name as name2_0_0_,
student0_.age as age3_0_0_,
student0_.sschool as sschool1_1_0_,
student0_.sscore as sscore2_1_0_
from
hedb.student student0_
where
student0_.id=?
Member [id=stu - 1, name=hhy, age=20]Student [sschool=xxx, sscore=120.0]
此时由于已经明确的设置好了要查询的数据类,所以直接查询具体的对应表。
但是现在有一个问题,既然是继承映射,那么所有的子类都是Member的子类,能不能够按照Member查询呢?
范例:按照Member查询数据
package org.lks.test;
import org.lks.dbc.HibernateSessionFactory;
import org.lks.pojo.Member;
public class TestMemberGet {
public static void