继承关系映射
继承是面向对象编程中一个很重要的特征,在做面向对象的分析与设计时,经常会设计出具体继承关联的持久化类,为了将这些持久化类之间的继承关系映射到关系数据库上,编程者采用了Hibernate中提供的三种常用的继承关系映射方案。
第一种:整个继承层次一张表
把整个继承层次的多个类的信息放到一张表里,需要在表中添加一个特定字段,用这个字段的值来进行区分哪些记录是属于哪个类的。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!-- 映射持久化类 -->
<class name="com.qiujy.domain.Singer" table="singer">
<!-- 映射对象标识符 -->
<id name="id" column="id" type="long">
<generator class="native" />
</id>
<!-- 指定鉴别器字段,要放置在所有属性映射之前 -->
<discriminator column="type" type="string" />
<!-- 映射普通属性 -->
<property name="name"/>
<property name="region"/>
<property name="description"/>
<!-- 映射子类,指定鉴别字段值 -->
<subclass name="com.qiujy.domain.SingleSinger"
discriminator-value="S">
<!-- 映射本子类的属性 -->
<property name="gender"/>
</subclass>
<!-- 映射子类,指定鉴别字段值 -->
<subclass name="com.qiujy.domain.Bands"
discriminator-value="B">
<!-- 映射本子类的属性 -->
<property name="leader"/>
</subclass>
</class>
</hibernate-mapping>
优点:在性能和简单方面都很好,在多态和非多态的查询上也很好,是继承映射中使用比较广泛的方案。
缺点:子类中属性的值必须是可以为空的。
第二种:每个子类一张表
把对象模型上的继承关系表示为关系模型中的外键关联,继承结构中的每个类和子类(包括抽象类和就口)都有一张对应的数据库表。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!-- 映射持久化类 -->
<class name="com.qiujy.domain.Singer" table="singer">
<!-- 映射对象标识符 -->
<id name="id" column="id" type="long">
<generator class="native" />
</id>
<!-- 映射普通属性 -->
<property name="name" />
<property name="region" />
<property name="description" />
<!-- 用joined-subclass元素给每个子类映射到一张表 -->
<joined-subclass name="com.qiujy.domain.SingleSinger"
table="single_singer">
<!-- 用key元素来指定子类和父类之间是通过哪个字段来关联的 -->
<key column="singler_id" />
<!-- 映射本子类的属性 -->
<property name="gender" />
</joined-subclass>
<!-- 用joined-subclass元素给每个子类映射到一张表 -->
<joined-subclass name="com.qiujy.domain.Bands"
table="bands">
<!-- 用key元素来指定子类和父类之间是通过哪个字段来关联的 -->
<key column="bands_id" />
<!-- 映射本子类的属性 -->
<property name="leader"/>
</joined-subclass>
</class>
</hibernate-mapping>
在父类对应的数据库中,实际上会存储所有的记录,包括父类和子类的记录;在子类对应的数据库中,这个表只能存储子类中所有的属性映射的字段值;子类与父类通过相同的主键值来关联。
子类中属性较多使用每个子类一张表
第三种:每个具体类一张表
这种策略师针对每个具体类对应一张表,而且这个表的信息是完备的,他包含所有从父类继承下来的属性映射的字段和自己的属性映射的字段。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!-- 指定此类为抽象类 -->
<class name="com.qiujy.domain.Singer" abstract="true">
<!-- 映射对象标识符 -->
<id name="id" column="id" type="long">
<!-- 映射主键生成方式为由Java应用程序负责生成标识符 -->
<generator class="assigned" />
</id>
<!-- 映射普通属性 -->
<property name="name" />
<property name="region" />
<property name="description" />
<!-- 用union-subclass元素给每个具体子类映射到一张表 -->
<union-subclass name="com.qiujy.domain.SingleSinger"
table="single_singer">
<!-- 映射本子类的属性 -->
<property name="gender" />
</union-subclass>
<!-- 用union-subclass元素给每个具体子类映射到一张表 -->
<union-subclass name="com.qiujy.domain.Bands"
table="bands">
<!-- 映射本子类的属性 -->
<property name="leader"/>
</union-subclass>
</class>
</hibernate-mapping>
注意:如果不需要多态查询:使用每个具体类一张表。
一定要使用哪个多态查询:子类中的属性相对较少,使用每个继承层次一张表。
子类中的属性较多,使用每个子类一张表。
简单的问题一般选择每个继承层次一张表,复杂案例一般选择每个子类一张表。