继承关系映射
继承是面向对象的重要的特征,在Hibernate中是以面向对象的思想进行持久化操作的。所以在Hibernate中,数据表所映射的实体的对象也是可以存在继承关系的。Hibernate中主要有3种继承映射关系:整个继承层次一张表,每个子类映射成一张表,每个具体类映射成为一张表。
下面是三种继承映射的使用:
JavaBean类:
父类:
package com.hbsi.domain;
public class Employee {
private int id;
private String name;
private Department depart;
public Department getDepart() {
return depart;
}
public void setDepart(Department depart) {
this.depart = depart;
}
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;
}
}
子类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;
}
}
子类Sales:
package com.hbsi.domain;
public class Sales extends Employee {
private int sell;
public int getSell() {
return sell;
}
public void setSell(int sell) {
this.sell = sell;
}
}
映射文件:
1、整个继承层次一张表
把整个继承层次的多个类的信息存放到一张表里。需要在表中添加一个特定字段,用这个字段的值来进行区分哪些记录是属于哪个类的。
<!--映射持久化类 指定鉴别字段值-->
<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"/>
<many-to-one name="depart" column="depart_id"/>
<!—用subclass映射子类,指定鉴别字段值 -->
<subclass name="Skiller" discriminator-value="1">
<!—映射本子类的属性 -->
<property name="skill"/>
</subclass>
<!—用subclass映射子类,指定鉴别字段值 -->
<subclass name="Sales" discriminator-value="2">
<!—映射本子类的属性 -->
<property name="sell"/>
</subclass>
</class>
这个映射方案在性能和简单性方面都很好,在多态和非多态的查询上也现得很好, 中继承映射中使用比较广泛的方案。但这个映射文件也有它的缺点:子类中属性的值必须是可以为空的。
2、每个子类一张表
这个方案是把对象模型上的继承关系表示为关系模型中的外键关联,继承结构中的每个类和子类(包括抽象类和接口)都有一张对应的数据库表。
<class name="Employee" table="employee">
<id name="id">
<generator class="native"/>
</id>
<property name="name" column="name"/>
<many-to-one name="depart" column="depart_id"/>
<!—用joined-subclass元素给每个子类映射到一张表 -->
<joined-subclass name="Skiller" table="skiller">
<!—用key元素来指定子类和父类之间是通过哪个字段来关联的-->
<key column="employee_id"/>
<!—映射本子类的属性 -->
<property name="skill"/>
</joined-subclass>
<!—用joined-subclass元素给每个子类映射到一张表 -->
<joined-subclass name="Sales" table="sales">
<!—用key元素来指定子类和父类之间是通过哪个字段来关联的-->
<key column="emplyee_id"/>
<!—映射本子类的属性 -->
<property name="sell"/>
</joined-subclass>
</class>
这种映射方案:在父类对应的数据库表中,实际上会存储所有的记录,包括父类和子类的记录在子类对应的数据库表中,这个表只存储子类中所特有的属性映射的字段值;子类与父类,通过相同的主键值来关联。
3、每个具体类一张表
这种策略是针对每个具体类对应一张表,而且这个表的信息是完备的,它包含所有从父类继承下来的属性映射的字段和自己的属性映射的字段。
<class name="Employee" table="employee">
<id name="id">
<generator class="hilo"/>
</id>
<property name="name" column="name"/>
<many-to-one name="depart" column="depart_id"/>
<!—用union-subclass元素给每个具体子类映射到一张表 -->
<union-subclass name="Skiller" table="skiller">
<!—映射本子类的属性 -->
<property name="skill"/>
</union-subclass>
<!—用union-subclass元素给每个具体子类映射到一张表 -->
<union-subclass name="Sales" table="sales">
<!—映射本子类的属性 -->
<property name="sell"/>
</union-subclass>
</class>
经验:
1、 如果不需要多态查询:使用每个具体类一张表;
2、 一定要使用多态查询:子类中的属性相对较少,使用每个继承层次一张表。
3、 子类中的属性较多,使用每个子类一张表。
4、 简单的问题一般选择每个继承层次一张表,复杂案例一般选择每个子类一张表。