Hibernate三种继承关系
1 简介
继承关系式关系型数据域面向对象数据结构之间的主要差异之一。如何在关系型数据库的基础之上,通过继承关系得到清晰合理的层次划分是Hibernate实体层次设计的一个关键问题。
Hibernate中支持三种类型的继承形式:
1. Table per concrete class
表与子类之间的独立一对一关系
2. Table per subclass
每个子类对应一张表,并与主类(父类)共享主表
3. Table per class hierarchy
表与类一对多关系,即所有类共享一张表
2 三种继承关系
下面我们结合一个实例分别就这3种情况进行介绍。
首先描述一下实例场景:
对于一个电子商务系统而言,在具备某些共性的同时(名称,厂商),不同类型的货物往往具备不同的属性,如书籍有页数属性,而DVD有区域码属性。在面向对象的设计中,我们通常将共性抽象为一个基类,而以不同的子类体现其具体特性。如下图:
那么,对于如上的类层次关系,反映到数据库的映射逻辑上是怎样的形式?下面我们围绕这个实例,对Hibernate中关于继承关系得3种映射类型进行讨论。
2.1Table per concrete class
------表与子类之间的独立一对一关系
在我们的实例中,TItem有两个子类:TBook、TDVD。那么,所谓“表与子类之间的独立一对一关系”,就是每个子表对应一张数据库表。对应TBook和TDVD,我们有以下库表。对应TBook和TDVD,所以有以下库表:
由于TBook、TDVD均由TItem继承而来,他们也自然继承了TItem中定义的id、name和manufacturer属性。在Table per concerete class模式中,每个子类都分别对应一个独立的表,这张表中包含了子类中所需的所有字段。
TBook/t_tbook和TDVD/t_tdvd可以看作是系统中两个独立的实体映射关系:
u TBook.hbm.xml
<hibernate-mapping
package="com.red.bean">
<classname="TBook" table="t_tbook">
<id name="id"column="id"type="integer">
<generator class="increment"></generator>
</id>
<propertyname="name"
column="name"
type="string"/>
<property name="manufacturer"
column="manufacturer"
type="string"/>
<property name="pageCount"
column="pageCount"
type="string"/>
</class>
</hibernate-mapping>
u TDVD.hbm.xml
<hibernate-mapping
package="com.red.bean">
<classname="TBook"table="t_tbook">
<id name="id"column="id"type="integer">
<generator class="increment"></generator>
</id>
<propertyname="name"
column="name"
type="string"/>
<property name="manufacturer"
column="manufacturer"
type="string"/>
<property name="pageCount"
column="pageCount"
type="string"/>
</class>
</hibernate-mapping>
u TItem.java
package com.red.bean;
import java.io.Serializable;
public class TItem implements Serializable {
private static final longs erialVersionUID = 1L;
private Integer id = 0;
private String name ="";
private String manufacturer ="";
public Integer getId() {
returnid;
}
publicvoid setId(Integer id) {
this.id = id;
}
public String getName() {
returnname;
}
publicvoid setName(String name) {
this.name = name;
}
public String getManufacturer() {
returnmanufacturer;
}
publicvoid setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
}
u TBook.java
package com.red.bean;
public class TBook extends TItem {
private static final long serial VersionUID = 1L;
private String pageCount ="";
public String getPageCount() {
returnpageCount;
}
publicvoid setPageCount(String pageCount) {
this.pageCount = pageCount;
}
}
u TDVD.java
package com.red.bean;
public class TDVD extends TItem {
private static final long serialVersionUID = 1L;
private String regionCode ="";
public String getRegionCode() {
returnregionCode;
}
publicvoid setRegionCode(String regionCode) {
this.regionCode = regionCode;
}
}
u 测试类TestTItemCase.java
package com.red.test;
import java.util.Iterator;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.red.bean.TBook;
import com.red.bean.TDVD;
import com.red.bean.TItem;
import junit.framework.TestCase;
public class TestTItemCase extends TestCase
{
private Session session =null;
private SessionFactory sf =null;
protectedvoid setUp()
{
try
{
Configuration cfg = new Configuration();
sf = cfg.configure().buildSessionFactory();
session = sf.openSession();
}
catch( HibernateException e)
{
e.printStackTrace();
}
}
protectedvoid tearDown()
{
try
{
session.close();
sf.close();
}
catch(HibernateException e)
{
e.printStackTrace();
}
}
publicvoid testInsert()
{
try
{
TBook tbook = new TBook();
tbook.setManufacturer("新华社");
tbook.setName("钢铁是怎样炼成的");
tbook.setPageCount("80");
TDVD tdvd = new TDVD();
tdvd.setManufacturer("魔音娱乐");
tdvd.setName("爱你一万年");
tdvd.setRegionCode("10");
session.beginTransaction();
session.save(tbook);
session.save(tdvd);
session.getTransaction().commit();
}
catch (HibernateException e)
{
e.printStackTrace();
}
}
publicvoid testSelect()
{
String hql = "from com.red.bean.TItem";
try
{
Query query = session.createQuery(hql);
List ls = query.list();
if (null == ls || ls.isEmpty())
{
return;
}
Iterator it = ls.iterator();
TItem item = null;
while (it.hasNext())
{
item = (TItem) it.next();
System.out.println(item.getName());
}
}
catch(HibernateException e)
{
e.printStackTrace();
}
}
}
可以看到,其映射方式与普通单表映射并没有什么不同,那么TBook和TDVD是否完全无瓜葛?
由于TBook和TDVD均继承了TItem类,在面向对象语义中,他们拥有共同的父类。这种关系在Hibernate中以多态(polymorphism)进行描述。同时我们看到,上面配置文件的class节点中并没有出现polymorphism属性设定,这也意味着,TBook和TDVD均采用了默认的隐式多态模式(polymorphism=”implicit”)(注意和显示多态模式的区别,见备注).
当我们执行HQL:“from TItem”时,Hibernate会自动在当前环境中查找所有polymorphism=”implicit”的子类,并返回子类所对应的所有库表记录。
执行TestTItemCase类,控制台打印的结果如下:
17:15:01,706 WARN RootClass:215 - composite-id class does not override hashCode(): com.red.bean.DoctorPK
17:15:02,166 DEBUG SQL:393 - select max(id) from t_tbook
17:15:02,206 DEBUG SQL:393 - select max(id) from t_tdvd
17:15:02,216 DEBUG SQL:393 - insert into t_tbook (name, manufacturer, pageCount, id) values (?, ?, ?, ?)
17:15:02,226 DEBUG SQL:393 - insert into t_tdvd (name, manufacturer, regionCode, id) values (?, ?, ?, ?)
17:15:02,246 WARN RootClass:215 - composite-id class does not override hashCode(): com.red.bean.DoctorPK
17:15:02,376 DEBUG SQL:393 - select tdvd0_.id as id11_, tdvd0_.name as name11_, tdvd0_.manufacturer as manufact3_11_, tdvd0_.regionCode as regionCode11_ from t_tdvd tdvd0_
17:15:02,376 DEBUG SQL:393 - select tbook0_.id as id10_, tbook0_.name as name10_, tbook0_.manufacturer as manufact3_10_, tbook0_.pageCount as pageCount10_ from t_tbook tbook0_
-----Item name:爱你一万年
-----Item name:钢铁是怎样炼成的
可以看到,Hibernate自动找到TItem的两个实体子类TBook和TDVD,并将查询出其全部记录(本实例中, t_tdvd表和t_tbook表中分别各存在一条名为“爱你一万年”和“钢铁是怎样炼成的”的商品记录)。
通过这样的方式,对象的继承关系在持久层得到了体现。
2.2Table per subclass
-------每个子类对应一张表,并与主类(父类)共享主表
这种关系中,将父类TItem单独映射到一张主表,而为TBook、TDVD类分别单独设立一张子表,子表中只包含子类所扩展的属性,同时,子类和父类通过关系型数据库的外键关联,如下图所示:
映射关系如下:
u 映射文件TItem.hbm.xml
<hibernate-mapping
package="com.red.bean">
<classname="TItem"table="t_titem">
<id name="id"column="id"type="integer">
<generator class="increment"></generator>
</id>
<propertyname="name"
column="name"
type="string"/>
<property name="manufacturer"
column="manufacturer"
type="string"/>
<joined-subclassname="TDVD"table="t_tdvd">
<key column="id"/>
<property name="regionCode"
column="regionCode"
type="string"/>
</joined-subclass>
<joined-subclass name="TBook"table="t_tbook">
<key column="id"/>
<property name="pageCount"
column="pageCount"
type="string"/>
</joined-subclass>
</class>
</hibernate-mapping>
joined-subclass和union-subclass区别,请参见2.4.2的内容。
u TItem.java
package com.red.bean;
import java.io.Serializable;
public class TItem implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id = 0;
private String name ="";
private String manufacturer ="";
public Integer getId() {
returnid;
}
publicvoid setId(Integer id) {
this.id = id;
}
public String getName() {
returnname;
}
publicvoid setName(String name) {
this.name = name;
}
public String getManufacturer() {
returnmanufacturer;
}
publicvoid setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
}
u TBook.java
package com.red.bean;
public class TBook extends TItem {
private static final long serialVersionUID = 1L;
private String pageCount ="";
public String getPageCount() {
returnpageCount;
}
publicvoid setPageCount(String pageCount) {
this.pageCount = pageCount;
}
}
u TDVD.java
package com.red.bean;
public class TDVD extends TItem {
private static final long serialVersionUID = 1L;
private String regionCode ="";
public String getRegionCode() {
returnregionCode;
}
publicvoid setRegionCode(String regionCode) {
this.regionCode = regionCode;
}
}
u TestTItemCase .java
package com.red.test;
import java.util.Iterator;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.red.bean.TBook;
import com.red.bean.TDVD;
import com.red.bean.TItem;
import junit.framework.TestCase;
public class TestTItemCase extends TestCase
{
private Session session =null;
private SessionFactory sf =null;
protectedvoid setUp()
{
try
{
Configuration cfg = new Configuration();
sf = cfg.configure().buildSessionFactory();
session = sf.openSession();
}
catch( HibernateException e)
{
e.printStackTrace();
}
}
protectedvoid tearDown()
{
try
{
session.close();
sf.close();
}
catch(HibernateException e)
{
e.printStackTrace();
}
}
publicvoid testInsert()
{
try
{
TBook tbook = new TBook();
tbook.setManufacturer("新华社");
tbook.setName("钢铁是怎样炼成的");
tbook.setPageCount("80");
TDVD tdvd = new TDVD();
tdvd.setManufacturer("魔音娱乐");
tdvd.setName("爱你一万年");
tdvd.setRegionCode("10");
session.beginTransaction();
session.save(tbook);
session.save(tdvd);
session.getTransaction().commit();
}
catch (HibernateException e)
{
e.printStackTrace();
}
}
publicvoid testSelect()
{
String itemhql = "from com.red.bean.TItem";
String bookhql = "from com.red.bean.TBook";
String dvdhql = "from com.red.bean.TDVD";
Query query = null;
List ls = null;
Iterator it = null;
try
{
//Item
query = session.createQuery(itemhql);
ls = query.list();
if (null == ls || ls.isEmpty())
{
return;
}
it = ls.iterator();
TItem item = null;
while (it.hasNext())
{
item = (TItem) it.next();
System.out.println("-----Item name:" + item.getName());
}
//Book
query = session.createQuery(bookhql);
ls = query.list();
if (null == ls || ls.isEmpty())
{
return;
}
it = ls.iterator();
TBook book = null;
while (it.hasNext())
{
book = (TBook) it.next();
System.out.println("-----Book name:" + book.getName());
}
//Book
query = session.createQuery(dvdhql);
ls = query.list();
if (null == ls || ls.isEmpty())
{
return;
}
it = ls.iterator();
TDVD dvd = null;
while (it.hasNext())
{
dvd = (TDVD) it.next();
System.out.println("-----DVD name:" + dvd.getName());
}
}
catch(HibernateException e)
{
e.printStackTrace();
}
}
}
执行TestTItemCase类,控制台打印的结果如下:
11:25:18,683 DEBUG SQL:393 - select max(id) from t_titem
11:25:18,744 DEBUG SQL:393 - insert into t_titem (name, manufacturer, id) values (?, ?, ?)
11:25:18,764 DEBUG SQL:393 - insert into t_tbook(pageCount, id) values (?, ?)
11:25:18,774 DEBUG SQL:393 - insert into t_titem(name, manufacturer, id) values (?, ?, ?)
11:25:18,774 DEBUG SQL:393 - insert into t_tdvd (regionCode, id) values (?, ?)
11:25:18,924 DEBUG SQL:393 - select titem0_.id as id12_, titem0_.name as name12_, titem0_.manufacturer as manufact3_12_, titem0_1_.regionCode as regionCode13_, titem0_2_.pageCount as pageCount14_, case when titem0_1_.id is not null then 1 when titem0_2_.id is not null then 2 when titem0_.id is not null then 0 end as clazz_ from t_titem titem0_ left outerjoin t_tdvd titem0_1_ on titem0_.id=titem0_1_.id left outerjoin t_tbook titem0_2_ on titem0_.id=titem0_2_.id
-----Item name:钢铁是怎样炼成的
-----Item name:爱你一万年
11:25:18,954 DEBUG SQL:393 - select tbook0_.id as id12_, tbook0_1_.name as name12_, tbook0_1_.manufacturer as manufact3_12_, tbook0_.pageCount as pageCount14_ from t_tbook tbook0_ innerjoin t_titem tbook0_1_ on tbook0_.id=tbook0_1_.id
-----Book name:钢铁是怎样炼成的
11:25:19,034 DEBUG SQL:393 - select tdvd0_.id as id12_, tdvd0_1_.name as name12_, tdvd0_1_.manufacturer as manufact3_12_, tdvd0_.regionCode as regionCode13_ from t_tdvd tdvd0_ innerjoin t_titem tdvd0_1_ on tdvd0_.id=tdvd0_1_.id
-----DVD name:爱你一万年
查看表数据
1. select*fromt_tdvd;
2. select*fromt_tbook;
3. select*fromt_titem;
2.3Table per class hierarchy
-------表与类一对多关系,即所有类共享一张表
在实际开发中通过冗余字段表达同类型数据可能是我们在绝大多数情况下的选择。对于上面的示例而言,我们通过一个包含所有子类的字段的t_titem表来存储所有商品信息。
这里的t_titem表不但包括了TItem的id、name、manufacturer字段,同时也包含了TDVD、TBook的regioncode、pagecount字段,不同类型的商品通过类型(category)字段加以区分。这样,无论是TDVD还是TBook类都可以在这张表中保存。假设:Category=1时,代表商品类型为书籍Category=2时,代表商品类型为DVD为了让Hibernate根据category自动识别对应class类型,我们需要在映射文件中进行配置,而discriminator(辨别识别)节点,则定义了这种配置关系。
u TItem.hbm.xml
<hibernate-mapping
package="com.red.bean">
<classname="TItem"table="t_titem">
<id name="id"column="id"type="integer">
<generator class="increment"></generator>
</id>
<!—声明discriminator字段,注意discriminator必须放在
id之后,property之前,原因见后面分析-->
<discriminator column="category" type="string"/>
<propertyname="name"
column="name"
type="string"/>
<property name="manufacturer"
column="manufacturer"
type="string"/>
<!—discriminator值-->
<subclass name="TDVD"discriminator-value="2">
<property name="regionCode"
column="regionCode"
type="string"/>
</subclass>
<!—discriminator值-->
<subclass name="TBook"discriminator-value="1">
<property name="pageCount"
column="pageCount"
type="string"/>
</subclass>
</class>
</hibernate-mapping>
其中:
1. 通过discriminator节点,我们声明了用作子类辨别标识的字段名
2. 指定当辨别字段值为1时,对应子类为TDVD
3. 指定当辨别字段值为2时,对应子类为TBook
u TItem.java
package com.red.bean;
import java.io.Serializable;
public class TItem implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id = 0;
private String name ="";
private String manufacturer ="";
public Integer getId() {
returnid;
}
publicvoid setId(Integer id) {
this.id = id;
}
public String getName() {
returnname;
}
publicvoid setName(String name) {
this.name = name;
}
public String getManufacturer() {
returnmanufacturer;
}
publicvoid setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
}
u TBook.java
package com.red.bean;
public class TBook extends TItem {
privatestaticfinallongserialVersionUID = 1L;
private StringpageCount ="";
public String getPageCount() {
returnpageCount;
}
publicvoid setPageCount(String pageCount) {
this.pageCount = pageCount;
}
}
u TDVD.java
package com.red.bean;
publicclass TDVD extends TItem {
privatestatic final long serialVersionUID = 1L;
private String regionCode ="";
public String getRegionCode() {
returnregionCode;
}
publicvoid setRegionCode(String regionCode) {
this.regionCode = regionCode;
}
}
u TestTItemCase.java
package com.red.test;
import java.util.Iterator;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.red.bean.TBook;
import com.red.bean.TDVD;
import com.red.bean.TItem;
import junit.framework.TestCase;
public class TestTItemCase extends TestCase {
private Session session =null;
private SessionFactory sf =null;
protectedvoid setUp()
{
try
{
Configuration cfg = new Configuration();
sf = cfg.configure().buildSessionFactory();
session = sf.openSession();
}
catch( HibernateException e)
{
e.printStackTrace();
}
}
protectedvoid tearDown()
{
try
{
session.close();
sf.close();
}
catch(HibernateException e)
{
e.printStackTrace();
}
}
publicvoid testInsert()
{
try
{
TBook tbook = new TBook();
tbook.setManufacturer("新华社");
tbook.setName("钢铁是怎样炼成的");
tbook.setPageCount("80");
TDVD tdvd = new TDVD();
tdvd.setManufacturer("魔音娱乐");
tdvd.setName("爱你一万年");
tdvd.setRegionCode("10");
session.beginTransaction();
session.save(tbook);
session.save(tdvd);
session.getTransaction().commit();
}
catch (HibernateException e)
{
e.printStackTrace();
}
}
publicvoid testSelect()
{
String itemhql = "from com.red.bean.TItem";
String bookhql = "from com.red.bean.TBook";
String dvdhql = "from com.red.bean.TDVD";
Query query = null;
List ls = null;
Iterator it = null;
try
{
//Item
query = session.createQuery(itemhql);
ls = query.list();
if (null == ls || ls.isEmpty())
{
return;
}
it = ls.iterator();
TItem item = null;
while (it.hasNext())
{
item = (TItem) it.next();
System.out.println("-----Item name:" + item.getName());
}
//Book
query = session.createQuery(bookhql);
ls = query.list();
if (null == ls || ls.isEmpty())
{
return;
}
it = ls.iterator();
TBook book = null;
while (it.hasNext())
{
book = (TBook) it.next();
System.out.println("-----Book name:" + book.getName());
}
//Book
query = session.createQuery(dvdhql);
ls = query.list();
if (null == ls || ls.isEmpty())
{
return;
}
it = ls.iterator();
TDVD dvd = null;
while (it.hasNext())
{
dvd = (TDVD) it.next();
System.out.println("-----DVD name:" + dvd.getName());
}
}
catch(HibernateException e)
{
e.printStackTrace();
}
}
}
执行测试类TestItemCase.java类,运行结果如下:
11:15:37,605 DEBUG SQL:393 - select max(id) from t_titem
11:15:37,656 DEBUG SQL:393 - insert into t_titem (name, manufacturer, pageCount, category, id) values (?, ?, ?, '1', ?)
11:15:37,666 DEBUG SQL:393 - insert into t_titem (name, manufacturer, regionCode, category, id) values (?, ?, ?, '2', ?)
11:15:37,826 DEBUG SQL:393 - select titem0_.id as id10_, titem0_.name as name10_, titem0_.manufacturer as manufact4_10_, titem0_.regionCode as regionCode10_, titem0_.pageCount as pageCount10_, titem0_.category as category10_ from t_titem titem0_
-----Item name:钢铁是怎样炼成的
-----Item name:爱你一万年
11:15:37,836 DEBUG SQL:393 - select tbook0_.id as id10_, tbook0_.name as name10_, tbook0_.manufacturer as manufact4_10_, tbook0_.pageCount as pageCount10_ from t_titem tbook0_ where tbook0_.category='1'
-----Book name:钢铁是怎样炼成的
11:15:37,836 DEBUG SQL:393 - select tdvd0_.id as id10_, tdvd0_.name as name10_, tdvd0_.manufacturer as manufact4_10_, tdvd0_.regionCode as regionCode10_ from t_titem tdvd0_ where tdvd0_.category='2'
-----DVD name:爱你一万年
查看表数据:
select *fromt_titem;
2.4 备注
2.4.1 隐身多态和显示多态的区别
多态的两个方式声明:
1、 显示多态:polymorphism=”explicit”
2、 隐式多态:polymorphism=”implicit”
多态两种方式是在hibernate类继承关系使用的,默认是隐式多态,只有显示指定polymorphism=”explicit”时,才是显示多态。
显示多态和隐式多态的区别(假设类A被指定为多态,B是A的父类):
1、 如果类A在*.hbm.xml文件中被显示指定polymorphism=”explicit”,那么,执行以下语句List objects = createQuery(“from类名”).list();只有“类名”是A时,才会查询到该类A对象的数据;
如果“类名”是其直接父类B或间接父类的名字,都查不到类A对象的数据。
2、 如果类A在*.hbm.xml文件中显示指定polymorphism=”implicit”或者没有做多态的设定,我们就认为是隐式多态,那么,执行以下语句List objects = createQuery(“from类名”).list();
无论“类名”是A还是B,还是B的父类,都能查到A类对象的数据。
下面以一个例子说明显示多态和隐式多态的区别: 隐式多态例子参见2.1章节的内容,下面仍以2.1例子为例来说明显示多态。
u TBook.hbm.xml
<hibernate-mapping
package="com.red.bean">
<!-- TBook 被声明为显示多态 -->
<classname="TBook"table="t_tbook" polymorphism="explicit">
<id name="id"column="id"type="integer">
<generator class="increment"></generator>
</id>
<propertyname="name"
column="name"
type="string"/>
<property name="manufacturer"
column="manufacturer"
type="string"/>
<property name="pageCount"
column="pageCount"
type="string"/>
</class>
</hibernate-mapping>
u TDVD.hbm.xml
<hibernate-mapping
package="com.red.bean">
<!-- TBook 被声明为隐式多态,默认是隐式多态 -->
<classname="TDVD"table="t_tdvd">
<id name="id"column="id"type="integer">
<generator class="increment"></generator>
</id>
<propertyname="name"
column="name"
type="string"/>
<property name="manufacturer"
column="manufacturer"
type="string"/>
<property name="regionCode"
column="regionCode"
type="string"/>
</class>
</hibernate-mapping>
u TTItem.java
package com.red.bean;
import java.io.Serializable;
public class TItem implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id = 0;
private String name ="";
private String manufacturer ="";
public Integer getId() {
returnid;
}
publicvoid setId(Integer id) {
this.id = id;
}
public String getName() {
returnname;
}
publicvoid setName(String name) {
this.name = name;
}
public String getManufacturer() {
returnmanufacturer;
}
publicvoid setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
}
u TBook.java
package com.red.bean;
public class TBook extends TItem {
private static final long serialVersionUID = 1L;
private String pageCount ="";
public String getPageCount() {
returnpageCount;
}
publicvoid setPageCount(String pageCount) {
this.pageCount = pageCount;
}
}
u TDVD.java
package com.red.bean;
public class TDVD extends TItem {
private static final long serialVersionUID = 1L;
private String regionCode ="";
public String getRegionCode() {
returnregionCode;
}
publicvoid setRegionCode(String regionCode) {
this.regionCode = regionCode;
}
}
u TestTItemCase.java
package com.red.test;
import java.util.Iterator;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.red.bean.TBook;
import com.red.bean.TDVD;
import com.red.bean.TItem;
import junit.framework.TestCase;
public class TestTItemCase extends TestCase {
private Session session =null;
private SessionFactory sf =null;
protectedvoid setUp()
{
try
{
Configuration cfg = new Configuration();
sf = cfg.configure().buildSessionFactory();
session = sf.openSession();
}
catch( HibernateException e)
{
e.printStackTrace();
}
}
protectedvoid tearDown()
{
try
{
session.close();
sf.close();
}
catch(HibernateException e)
{
e.printStackTrace();
}
}
publicvoid testInsert()
{
try
{
TBook tbook = new TBook();
tbook.setManufacturer("新华社");
tbook.setName("钢铁是怎样炼成的");
tbook.setPageCount("80");
TDVD tdvd = new TDVD();
tdvd.setManufacturer("魔音娱乐");
tdvd.setName("爱你一万年");
tdvd.setRegionCode("10");
session.beginTransaction();
session.save(tbook);
session.save(tdvd);
session.getTransaction().commit();
}
catch (HibernateException e)
{
e.printStackTrace();
}
}
publicvoid testSelect()
{
String itemhql = "from com.red.bean.TItem";
String bookhql = "from com.red.bean.TBook";
String dvdhql = "from com.red.bean.TDVD";
Query query = null;
List ls = null;
Iterator it = null;
try
{
//Item
query = session.createQuery(itemhql);
ls = query.list();
if (null == ls || ls.isEmpty())
{
return;
}
it = ls.iterator();
TItem item = null;
while (it.hasNext())
{
item = (TItem) it.next();
System.out.println("-----Item name:" + item.getName());
}
//Book
query = session.createQuery(bookhql);
ls = query.list();
if (null == ls || ls.isEmpty())
{
return;
}
it = ls.iterator();
TBook book = null;
while (it.hasNext())
{
book = (TBook) it.next();
System.out.println("-----Book name:" + book.getName());
}
//Book
query = session.createQuery(dvdhql);
ls = query.list();
if (null == ls || ls.isEmpty())
{
return;
}
it = ls.iterator();
TDVD dvd = null;
while (it.hasNext())
{
dvd = (TDVD) it.next();
System.out.println("-----DVD name:" + dvd.getName());
}
}
catch(HibernateException e)
{
e.printStackTrace();
}
}
}
执行测试类TestTItemCase,控制台打印的结果如下:
12:47:31,371 DEBUG SQL:393 - select max(id) from t_tbook
12:47:31,422 DEBUG SQL:393 - select max(id) from t_tdvd
12:47:31,442 DEBUG SQL:393 - insert into t_tbook (name, manufacturer, pageCount, id) values (?, ?, ?, ?)
12:47:31,452 DEBUG SQL:393 - insert into t_tdvd (name, manufacturer, regionCode, id) values (?, ?, ?, ?)
12:47:31,642 DEBUG SQL:393 - select tdvd0_.id as id11_, tdvd0_.name as name11_, tdvd0_.manufacturer as manufact3_11_, tdvd0_.regionCode as regionCode11_ from t_tdvd tdvd0_
-----Item name:爱你一万年
12:47:31,662 DEBUG SQL:393 - select tbook0_.id as id10_, tbook0_.name as name10_, tbook0_.manufacturer as manufact3_10_, tbook0_.pageCount as pageCount10_ from t_tbook tbook0_
-----Book name:钢铁是怎样炼成的
12:47:31,672 DEBUG SQL:393 - select tdvd0_.id as id11_, tdvd0_.name as name11_, tdvd0_.manufacturer as manufact3_11_, tdvd0_.regionCode as regionCode11_ from t_tdvd tdvd0_
-----DVD name:爱你一万年
通过上面的例子可以看到类TBook类被指定为显示多态,TDVD类被指定为隐式多
态,在执行String itemhql ="from com.red.bean.TItem";查询结果是,获得只有TDVD对象的数据。只有在明确执行String bookhql = "from com.red.bean.TBook";才能查询到TBook的对象数据。
2.4.1 joined-subclass和union-subclass区别
joined-subclass和uion-subclass都是在类和表的继承映射中使用到的,下面以两张图来区分它们:
图2.4.2.1
图2.4.2.2
其中,图2.4.2.1是使用uion-subclass元素映射后的类表结构,图2.4.2.2是使用joined-subclass元素映射后的表结构,它们的共同点是要为每个表映射一张表,包括子类和父类。不同点是使用uion-subclass元素后,子类映射的表中要同时包含父类表中的字段,而使用joined-subclass元素不需要。
u TBook.hbm.xml
<hibernate-mapping
package="com.red.bean">
<classname="TItem"table="t_titem">
<id name="id"column="id"type="integer">
<generator class="increment"></generator>
</id>
<propertyname="name"
column="name"
type="string"/>
<property name="manufacturer"
column="manufacturer"
type="string"/>
<union-subclass name="TDVD"table="t_tdvd">
<property name="regionCode"
column="regionCode"
type="string"/>
</union-subclass>
<union-subclass name="TBook"table="t_tbook">
<property name="pageCount"
column="pageCount"
type="string"/>
</union-subclass>
</class>
</hibernate-mapping>
u TItem.java
package com.red.bean;
import java.io.Serializable;
public class TItem implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id = 0;
private String name ="";
private String manufacturer ="";
public Integer getId() {
returnid;
}
publicvoid setId(Integer id) {
this.id = id;
}
public String getName() {
returnname;
}
publicvoid setName(String name) {
this.name = name;
}
public String getManufacturer() {
returnmanufacturer;
}
publicvoid setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
}
u TBook.java
package com.red.bean;
public class TBook extends TItem {
private static final long serialVersionUID = 1L;
private String pageCount ="";
public String getPageCount() {
returnpageCount;
}
publicvoid setPageCount(String pageCount) {
this.pageCount = pageCount;
}
}
u TDVD.java
package com.red.bean;
public class TDVD extends TItem {
private static final long serialVersionUID = 1L;
private String regionCode ="";
public String getRegionCode() {
returnregionCode;
}
publicvoid setRegionCode(String regionCode) {
this.regionCode = regionCode;
}
}
u 测试类TestTItemCase.java
package com.red.test;
import java.util.Iterator;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.red.bean.TBook;
import com.red.bean.TDVD;
import com.red.bean.TItem;
import junit.framework.TestCase;
public class TestTItemCase extends TestCase {
private Session session =null;
private SessionFactory sf =null;
protectedvoid setUp()
{
try
{
Configuration cfg = new Configuration();
sf = cfg.configure().buildSessionFactory();
session = sf.openSession();
}
catch( HibernateException e)
{
e.printStackTrace();
}
}
protectedvoid tearDown()
{
try
{
session.close();
sf.close();
}
catch(HibernateException e)
{
e.printStackTrace();
}
}
publicvoid testInsert()
{
try
{
TBook tbook = new TBook();
tbook.setManufacturer("新华社");
tbook.setName("钢铁是怎样炼成的");
tbook.setPageCount("80");
TDVD tdvd = new TDVD();
tdvd.setManufacturer("魔音娱乐");
tdvd.setName("爱你一万年");
tdvd.setRegionCode("10");
TItem tit = new TItem();
tit.setName("xxxx");
tit.setManufacturer("yyyyy");
session.beginTransaction();
session.save(tbook);
session.save(tdvd);
session.save(tit);
session.getTransaction().commit();
}
catch (HibernateException e)
{
e.printStackTrace();
}
}
publicvoid testSelect()
{
String itemhql = "from com.red.bean.TItem";
String bookhql = "from com.red.bean.TBook";
String dvdhql = "from com.red.bean.TDVD";
Query query = null;
List ls = null;
Iterator it = null;
try
{
//Item
query = session.createQuery(itemhql);
ls = query.list();
if (null == ls || ls.isEmpty())
{
return;
}
it = ls.iterator();
TItem item = null;
while (it.hasNext())
{
item = (TItem) it.next();
System.out.println("-----Item name:" + item.getName());
}
//Book
query = session.createQuery(bookhql);
ls = query.list();
if (null == ls || ls.isEmpty())
{
return;
}
it = ls.iterator();
TBook book = null;
while (it.hasNext())
{
book = (TBook) it.next();
System.out.println("-----Book name:" + book.getName());
}
//Book
query = session.createQuery(dvdhql);
ls = query.list();
if (null == ls || ls.isEmpty())
{
return;
}
it = ls.iterator();
TDVD dvd = null;
while (it.hasNext())
{
dvd = (TDVD) it.next();
System.out.println("-----DVD name:" + dvd.getName());
}
}
catch(HibernateException e)
{
e.printStackTrace();
}
}
}
执行TestTItemCase类,控制台打印的结果如下:
13:44:43,906 DEBUG SQL:393 - select max(ids_.id) from ( select id from t_tdvd union select id from t_tbook union select id from t_titem ) ids_
13:44:43,976 DEBUG SQL:393 - insert into t_tbook (name, manufacturer, pageCount, id) values (?, ?, ?, ?)
13:44:43,986 DEBUG SQL:393 - insert into t_tdvd(name, manufacturer, regionCode, id) values (?, ?, ?, ?)
13:44:43,986 DEBUG SQL:393 - insert into t_titem(name, manufacturer, id) values (?, ?, ?)
13:44:44,157 DEBUG SQL:393 - select titem0_.id as id12_, titem0_.name as name12_, titem0_.manufacturer as manufact3_12_, titem0_.regionCode as regionCode13_, titem0_.pageCount as pageCount14_, titem0_.clazz_ as clazz_ from ( select id, null as pageCount, manufacturer, name, null as regionCode, 0 as clazz_ from t_titem union select id, null as pageCount, manufacturer, name, regionCode, 1 as clazz_ from t_tdvd union select id, pageCount, manufacturer, name, null as regionCode, 2 as clazz_ from t_tbook ) titem0_
-----Item name:钢铁是怎样炼成的
-----Item name:爱你一万年
-----Item name:xxxx
13:44:44,167 DEBUG SQL:393 - select tbook0_.id as id12_, tbook0_.name as name12_, tbook0_.manufacturer as manufact3_12_, tbook0_.pageCount as pageCount14_ from t_tbook tbook0_
-----Book name:钢铁是怎样炼成的
13:44:44,177 DEBUG SQL:393 - select tdvd0_.id as id12_, tdvd0_.name as name12_, tdvd0_.manufacturer as manufact3_12_, tdvd0_.regionCode as regionCode13_ from t_tdvd tdvd0_
-----DVD name:爱你一万年
查看表数据
1. select*fromt_tdvd;
2. select*fromt_tbook;
3. select*fromt_titem;