hibernate中支持3种类型的继承形式
- Table per concrete class
表与子类中的一对一关系
- Table per subclass
每个子类对应一张子表,并与主类共享主表
- Table per class hierarchy
表与类的一对多关系

现在我们围绕这个实例,对hibernate中关于继承关系的3种映射类型进行讨论
- Table per concrete class
在这个实例中,TItem有两个子类,分别是TBook和TDVD,所谓的表与子类中的一对一关系,也就是说每个子类对应一张数据库表,那么我们需要两个*.hbm.xml文件


这个和我们之前的设计很相似,不过大家也看出了吧..有点不现实..冗余太多了
- Table per subclass
从上面的设计我们看出冗余太对,那么我们自然就会想到把重复的字段提取出来,做为一张主表,TBook,TDVD做为他们的子表,通过ID进行关联

然后写POJO类,TItem,TBook,TDVD具体我就不多说了,
TBook和TDVD继承TItem的
主要说一下TItem.hbm.xml这个文件,我们虽然表有3张,但却只有一个映射文件
<hibernate-mapping>
<class name="org.luna.hibernate.demo2.TItem" table="TITEM" schema="SCOTT">
<id name="id" type="java.lang.String">
<column name="ID" length="32" />
<generator class="assigned" />
</id>
<class name="org.luna.hibernate.demo2.TItem" table="TITEM" schema="SCOTT">
<id name="id" type="java.lang.String">
<column name="ID" length="32" />
<generator class="assigned" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" length="20" not-null="true" />
</property>
<property name="manufacturer" type="java.lang.String">
<column name="MANUFACTURER" length="20" />
</property>
<joined-subclass name="org.luna.hibernate.demo2.TBook" table="TBOOK">
<key column="ID"></key>
<property name="pageCount" type="java.lang.Integer" column="pagecount"></property>
</joined-subclass>
<joined-subclass name="org.luna.hibernate.demo2.TDVD" table="TDVD">
<key column="ID"></key>
<property name="regioncode" type="java.lang.String" column="regioncode"></property>
</joined-subclass>
</class>
</hibernate-mapping>
从上面的代码中我们看到了多了一个标签
joined-subclass
,这个标签表示关系,
他的
name
属性表示对应的哪个类,
table
是哪张表,他下面有个
Key
的标签,这个表示他们是通过什么来进行关联的.而
Key
下的
column
表示他们是通过哪个字段来进行关联的,这里我们是ID,然后他下面就不多说了..大家一看就明白了.
然后我们进行操作,写一个
TItemOperate
的类,他下面有个
insert
方法
public void insert(TItem tItem){
session.save(tItem);
session.beginTransaction().commit();
session.close();
}
session.save(tItem);
session.beginTransaction().commit();
session.close();
}
然后我们再建个TestHibernate的类,来测试一下,这是
main
下的代码,
TItemOperate to = new TItemOperate();
// 我们在这里试下插入一本书
// TBook tBook = new TBook();
// tBook.setId("first");
// tBook.setName("Luna");
// tBook.setManufacturer("shenzhen");
// tBook.setPageCount(500);
//
// to.insert(tBook);
// 我们试下插入一张DVD
// TDVD tDVD = new TDVD();
// tDVD.setId("next");
// tDVD.setName("火影228");
// tDVD.setManufacturer("日本");
// tDVD.setRegioncode("no");
//
// to.insert(tDVD);
// TBook tBook = new TBook();
// tBook.setId("first");
// tBook.setName("Luna");
// tBook.setManufacturer("shenzhen");
// tBook.setPageCount(500);
//
// to.insert(tBook);
// 我们试下插入一张DVD
// TDVD tDVD = new TDVD();
// tDVD.setId("next");
// tDVD.setName("火影228");
// tDVD.setManufacturer("日本");
// tDVD.setRegioncode("no");
//
// to.insert(tDVD);
我们能发现,他会自动关联,插入了主表后,子表一样能加进去,因为表删了,没能给大家看效果,有兴趣的人可以自己去试下.你会发现,主表和子表的ID名一样,共有信息他会保存的主表,子表的专有信息他会保存到子表去.
但现在又有个问题,这真的是唯一的吗?
此设计不是解决此类问题的唯一标准
- Table per class hierarchy
我们来看看这张图

从这张表我们能看把TDVD和TBOOK表中的信息都加到这张表中,然后用
category
进行区分

我们第一行
category
的值是
1 ,
表示
书
,而他的
regioncode
的值为
null
我们第二行
category
的值为
2 ,
表示
DVD ,
而他的
pagecount
的值为
null
我们来看看在hibernate中是怎么实现的
还是来看看我们最关心的
TItem.hbm.xml
这个文件吧..
<hibernate-mapping>
<class name="org.luna.hibernate.demo3.TItem" table="TITEM" schema="SCOTT">
<id name="id" type="java.lang.String">
<column name="ID" length="32" />
<generator class="assigned" />
</id>
<class name="org.luna.hibernate.demo3.TItem" table="TITEM" schema="SCOTT">
<id name="id" type="java.lang.String">
<column name="ID" length="32" />
<generator class="assigned" />
</id>
<discriminator column="category" type="java.lang.String"></discriminator>
<property name="name" type="java.lang.String">
<column name="NAME" length="20" not-null="true" />
</property>
<property name="manufacturer" type="java.lang.String">
<column name="MANUFACTURER" length="20" not-null="true" />
</property>
<property name="name" type="java.lang.String">
<column name="NAME" length="20" not-null="true" />
</property>
<property name="manufacturer" type="java.lang.String">
<column name="MANUFACTURER" length="20" not-null="true" />
</property>
<subclass name="org.luna.hibernate.demo3.TBook" discriminator-value="1">
<property name="pageCount" type="int">
<column name="PAGECOUNT" precision="22" scale="0" />
</property>
</subclass>
<subclass name="org.luna.hibernate.demo3.TDVD" discriminator-value="2">
<property name="regioncode" type="java.lang.String">
<column name="REGIONCODE" length="2" />
</property>
</subclass>
</class>
</hibernate-mapping>
</hibernate-mapping>
这里我们用到了 discriminator (识别器)
这个标签,说也不好说.识别器字段包含标志值,用于告知持久化层应该为某个特定的行创建哪一个子类的实例. 详细的话请看 http://www.hibernate.org/hib_docs/reference/zh-cn/html/mapping.html
里面有很详细的介绍
subclass也不多说了,表示子类,他里面有个
discriminator-value ,用来区别不同子类的值
discriminator-value(辨别值) (可选 - 默认和类名一样):一个用于区分不同的子类的值,在多态行为时使用。
然后我们用上面那个
TItemOperate
这个类
public class TestDemo03 {
public static void main(String[] args) {
TItemOperate to = new TItemOperate();
// TBook tBook = new TBook();
// tBook.setId("luna008");
// tBook.setName("luna");
// tBook.setManufacturer("深圳");
// tBook.setPageCount(500);
// to.insert(tBook);
TDVD tDVD = new TDVD();
tDVD.setId("LunaDVD");
tDVD.setName("luna");
tDVD.setManufacturer("深圳");
tDVD.setRegioncode("12");
to.insert(tDVD);
}
TItemOperate to = new TItemOperate();
// TBook tBook = new TBook();
// tBook.setId("luna008");
// tBook.setName("luna");
// tBook.setManufacturer("深圳");
// tBook.setPageCount(500);
// to.insert(tBook);
TDVD tDVD = new TDVD();
tDVD.setId("LunaDVD");
tDVD.setName("luna");
tDVD.setManufacturer("深圳");
tDVD.setRegioncode("12");
to.insert(tDVD);
}
}
你会发现你得到数据和刚开始的那个效果一样.