Hibernate高级映射 --- 继承映射
一 概念
继承是面向对象编程中一个很重要的特征,在做面向对象的分析与设计时,经常会设计出具体继承关联的持久化类。
二 四种常用的映射方式
1.设计整个的继承体现就用一张表 employee
属性为id,name,depart_id,type,skill,sell
0 null null
1 coding null
2 null 100
说明:type是鉴别器,type中0表示普通员工,1表示技术员工,2表示销售员工
(1)创建父类 Employee
package com.hbsi.domain;
public class Employee {
private int id;
private String name;
public Employee() {
super();
// TODO Auto-generated constructor stub
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Department getDepart() {
return depart;
}
public void setDepart(Department depart) {
this.depart = depart;
}
}
(2)创建子类 Skiller
package com.hbsi.domain;
public class Skiller extends Employee {
private String skill;
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
}
(3)创建子类 Sales
package com.hbsi.domain;
public class Sales extends Employee {
private Integer sell;
public Integer getSell() {
return sell;
}
public void setSell(Integer sell) {
this.sell = sell;
}
}
(4)映射一张表:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hbsi.domain">
<!-- discriminator-value="0"指定鉴别器在什么的时候属于哪个类型 -->
<class name="Employee" table="employee" discriminator-value="0">
<id name="id" column="id">
<generator class="native" />
</id>
<!-- 定义鉴别器,缺省的类型是字符串类型 鉴别器的位置应该在前面 -->
<discriminator column="type" type="int"/>
<property name="name" column="name" />
<!-- 用来描述子类,是继承映射 -->
<subclass name="Skiller" discriminator-value="1">
<property name="skill"></property>
</subclass>
<subclass name="Sales" discriminator-value="2">
<property name="sell"></property>
</subclass>
</class>
</hibernate-mapping>
(5)持久化类
package com.hbsi.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.hbsi.domain.Department;
import com.hbsi.domain.Employee;
import com.hbsi.domain.Sales;
import com.hbsi.domain.Skiller;
import com.hbsi.hibernate.utils.HibernateUtil;
public class TestExtends {
public static void main(String[] args) {
//add();
query(19);
}
static void add() {
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.beginTransaction();
// 普通员工
Employee emp1 = new Employee();
emp1.setName("aaa");
emp1.setDepart(depart);
// 技术员工
Skiller emp2 = new Skiller();
emp2.setName("bbb");
emp2.setDepart(depart);
emp2.setSkill("coding");
// 销售员工
Sales emp3 = new Sales();
emp3.setName("ccc");
emp3.setDepart(depart);
emp3.setSell(1000);
session.save(emp1);
session.save(emp2);
session.save(emp3);
transaction.commit();
} finally {
if (session != null) {
session.close();
}
}
}
//查询
static void query(int id) {
Session session = null;
try {
session = HibernateUtil.getSession();
//多态查询
Employee employee = (Employee) session.get(Employee.class, id);
System.out.println(employee.getName()+":"+employee.getClass());
//查询出子类中的属性
if(employee instanceof Skiller){
((Skiller) employee).getSkill();
}else if(employee instanceof Sales){
((Sales) employee).getSell();
}
} finally {
if (session != null) {
session.close();
}
}
}
}
思考:
优点:在性能和简单性方面都很好,在多态和非多态的查询上也表现的很好,是继承映射中使用比较广泛的方案。
缺点:如果Skill中有多个属性来描述,那么在员工的表中有5个字段为空的,如果Sales中也有多个属性,也会出现大量的null值,这种映射方案的关系模型表设计业违背了第三范式。
2.每个子类一张表(joined-subclass),存放的是子类所特有的属性
Employee Skiller Salles
Id name depar_id employee_id,skill employee_id,sell
映射文件为:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hbsi.domain">
<!-- 继承映射第二种 单独映射为一张表 -->
<class name="Employee" table="employee1">
<id name="id">
<generator class="native"></generator>
</id>
<property name="name" column="name" />
<many-to-one name="depart" column="depart_id"/>
<!-- 单独映射成一张表,来描述特有的属性 -->
<joined-subclass name="Skiller" table="skiller">
<key column="employee_id"></key>
<property name="skill"></property>
</joined-subclass>
<joined-subclass name="Sales" table="sales">
<key column="employee_id"></key>
<property name="sell"></property>
</joined-subclass>
</class>
</hibernate-mapping>
思考:
这种效率是不高的,因为在多态查询的时候要同时连接三张表,如果再增加一个子类,那么在关系模型中增加了一个表,多态的查询要四张表,如果是更多呢?
但是这种方式采用的设计模式是合理的,可效率不高
3.混合使用”一个类继承体系一张表”和”每个子类一张表”,
Employee sales
Id,name,dpart_id,type skill employee_id,sell
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hbsi.domain">
<!-- 第三种 :前两种的混合-->
<class name="Employee" table="employee2" discriminator-value="0">
<id name="id">
<generator class="native"></generator>
</id>
<!-- 鉴别器 -->
<discriminator column="type" type="int"/>
<property name="name" column="name" />
<many-to-one name="depart" column="depart_id"/>
<subclass name="Skiller" discriminator-value="1">
<property name="skill"/>
</subclass>
<subclass name="Sales" discriminator-value="2">
<join table="sales1">
<key column="employee_id"/>
<property name="sell"/>
</join>
</subclass>
</class>
</hibernate-mapping>
4.每个具体类是一张完整的表(union-subclass),保存子类完整的信息
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hbsi.domain">
<!-- 第四种 每一个表都是完整的表 -->
<class name="Employee" table="employee4">
<id name="id">
<!-- 表示高地位的主键生成器 形成唯一的主键 -->
<generator class="hilo"/>
</id>
<property name="name" column="name" />
<many-to-one name="depart" column="depart_id"/>
<!-- 连接 -->
<union-subclass name="Skiller" table="skiller4">
<property name="skill"></property>
</union-subclass>
<union-subclass name="Sales" table="sale4">
<property name="sell"></property>
</union-subclass>
</class>
</hibernate-mapping>
总体的建议:表的数量不要超过类的数量