导读:
- 什么是继承映射?
- 继承映射的分类
- 所有类形成一张表
- 每个类形成一张表
- 只有子类生成表,父类不生成表
什么是继承映射
实体类之间互相有继承关系,或者说多个实体类有公共部分,可以抽象出一个父类。这是对象之间的关系,可是数据表存储不一定是一个类对应一张表,因此我们需要分类讨论一下。
继承映射的分类
上面已经说过了,一共分成三种情况,其实对象之间的关系没有变,这三种情况都是表达了数据表的对应关系。
在讲具体每种情况前,先把各实体类代码贴出来:
Animal.java
package entity;
public class Animal {
private int id;
private String name;
private boolean sex;
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 boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
}
Pig.java
package entity;
public class Pig extends Animal{
private int weight;
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}
Dog.java
package entity;
public class Dog extends Animal{
private int run;
public int getRun() {
return run;
}
public void setRun(int run) {
this.run = run;
}
}
1.所有类形成一张表
Animal.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Animal" table="_animal">
<id name="id">
<generator class="native"/>
</id>
<!-- 下面就开始定义就是将pig和dog继承进来,都生成一张表 -->
<!-- 下面的这个类型string是hibernate的,不是java自己的String类型 -->
<!-- discriminator这个标签必须写在所有属性的第一个,要不然会报错! -->
<discriminator column="type" type="string" />
<property name="name" />
<property name="sex" />
<subclass name="entity.Pig" discriminator-value="P">
<property name="weight"></property>
</subclass>
<subclass name="entity.Dog" discriminator-value="D">
<property name="run"></property>
</subclass>
</class>
</hibernate-mapping>
单元测试:
package entity;
import org.hibernate.classic.Session;
import junit.framework.TestCase;
import util.hibernateUtil;
/**
* 测试目的:
* 这是继承映射的第一种策略,多个类共同对应一张表。
* 1. 用不同的子类去查询数据
* 2. 用父类多态的角度去查询
* 3. 根据不同的类查询出来结果,因为涉及到延迟加载,看是否能判断真实类类型
*
* 结果:
* 只要是查询的时候不延时,那就能判断实际的对象类型
* @author arkulo
*
*/
public class TestDemo extends TestCase {
// 初始化数据
public void test1()
{
Session session = null;
try {
session = hibernateUtil.getSession();
session.beginTransaction();
Dog dd = new Dog();
dd.setName("叮当");
dd.setSex(false);
dd.setRun(100);
session.save(dd);
Pig zz = new Pig();
zz.setName("八戒");
zz.setSex(false);
zz.setWeight(60);
session.save(zz);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
hibernateUtil.closeSession(session);
}
}
// 用父类多态角度去查询
public void test2()
{
test1();
System.out.println("----------------------------");
Session session = null;
try {
session = hibernateUtil.getSession();
session.beginTransaction();
// load是延迟加载,所以用的是代理,因此不能判断对象的类型是Dog
// 如果必须判断真实对象类型,那就该用get函数,或者把class的lazy属性设置成为false
// Animal an = (Animal)session.load(Animal.class, 1);
// if(an instanceof Dog)
// {
// System.out.println("我是小狗,我叫:"+an.getName());
// }else
// {
// System.out.println("我是小猪,我叫"+an.getName());
// }
Dog dd = (Dog)session.get(Dog.class, 1);
System.out.println(dd.getName());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
hibernateUtil.closeSession(session);
}
}
}
2.每个类形成一张表
Animal.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="entity">
<class name="entity.Animal" table="_animal">
<id name="id">
<generator class="native"/>
</id>
<property name="name" />
<property name="sex" />
<!-- 下面就是各个实体类单独程表的映射配置 -->
<!-- pid是关联animal表的主键,did同理 -->
<joined-subclass name="Pig" table="_pig">
<key column="pid"></key>
<property name="weight"></property>
</joined-subclass>
<joined-subclass name="Dog" table="_dog">
<key column="did"></key>
<property name="run"></property>
</joined-subclass>
</class>
</hibernate-mapping>
单元测试:
package entity;
import org.hibernate.classic.Session;
import junit.framework.TestCase;
import util.hibernateUtil;
/**
* 这个项目是多个关联实体类,每个实体类映射成为一张表,但是只用一个hbm映射文件
* 插入数据的时候,相当于主附表
*
* @author arkulo
*
*/
public class TestDemo extends TestCase {
// 初始化数据
public void test1()
{
Session session = null;
try {
session = hibernateUtil.getSession();
session.beginTransaction();
// 产生两天sql语句,一条插入Animal表,一条插入Dog表,did字段关联animal表的主键
Dog dd = new Dog();
dd.setName("叮当");
dd.setSex(false);
dd.setRun(100);
session.save(dd);
// 和上面同理,产生两条SQL语句
Pig zz = new Pig();
zz.setName("八戒");
zz.setSex(false);
zz.setWeight(60);
session.save(zz);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
hibernateUtil.closeSession(session);
}
}
// 用父类多态角度去查询
public void test2()
{
test1();
System.out.println("----------------------------");
Session session = null;
try {
session = hibernateUtil.getSession();
session.beginTransaction();
// load是延迟加载,所以用的是代理,因此不能判断对象的类型是Dog
// 如果必须判断真实对象类型,那就该用get函数,或者把class的lazy属性设置成为false
// sql语句是left out join,一条SQL语句联合查询两张表
// Animal an = (Animal)session.load(Animal.class, 1);
// if(an instanceof Dog)
// {
// System.out.println("我是小狗,我叫:"+an.getName());
// }else
// {
// System.out.println("我是小猪,我叫"+an.getName());
// }
// 采用inner join的方式,发出一条sql语句,关联查询animal和dog表
// Dog dd = (Dog)session.get(Dog.class, 1);
// System.out.println(dd.getName());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
hibernateUtil.closeSession(session);
}
}
}
3.只有子类生成表,父类不生成表
Animal.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="entity">
<!-- abstract设置为true,animal实体类就不会建表,但不会影响到存储和加载 -->
<class name="entity.Animal" abstract="true">
<id name="id">
<!-- 这里不会生成表了,所以id就不能采用数据库生成策略 -->
<generator class="assigned"/>
</id>
<property name="name" />
<property name="sex" />
<!-- 下面开始配置子类生成独立的表 -->
<union-subclass name="Pig" table="_pig">
<property name="weight"></property>
</union-subclass>
<union-subclass name="Dog" table="_dog">
<property name="run"></property>
</union-subclass>
</class>
</hibernate-mapping>
单元测试:
package entity;
import org.hibernate.classic.Session;
import junit.framework.TestCase;
import util.hibernateUtil;
/**
* 三个类,每个具体类映射成一张表,父类不映射成表
*
* @author arkulo
*
*/
public class TestDemo extends TestCase {
// 初始化数据
public void test1()
{
Session session = null;
try {
session = hibernateUtil.getSession();
session.beginTransaction();
// 这里要注意,id是由animal提供的,但是animal现在不会在去生成表了,因此
// 这里的主键,我们只能自己指定,不能依靠数据库生成,当然也可以使用uuid,那就需要设置id为String类型
Dog dd = new Dog();
dd.setId(1);
dd.setName("叮当");
dd.setSex(false);
dd.setRun(100);
session.save(dd);
// 和上面同理
Pig zz = new Pig();
zz.setId(2);
zz.setName("八戒");
zz.setSex(false);
zz.setWeight(60);
session.save(zz);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
hibernateUtil.closeSession(session);
}
}
// 用父类多态角度去查询
public void test2()
{
// 这里如果用上面的函数来初始化数据,记得重新指定id,因为是手动设定的
test1();
System.out.println("----------------------------");
Session session = null;
try {
session = hibernateUtil.getSession();
session.beginTransaction();
// load是延迟加载,所以用的是代理,因此不能判断对象的类型是Dog
// 如果必须判断真实对象类型,那就该用get函数,或者把class的lazy属性设置成为false
// sql语句是left out join,一条SQL语句联合查询两张表
Animal an = (Animal)session.get(Animal.class, 1);
if(an instanceof Dog)
{
System.out.println("我是小狗,我叫:"+an.getName());
}else
{
System.out.println("我是小猪,我叫"+an.getName());
}
// 采用inner join的方式,发出一条sql语句,关联查询animal和dog表
// Dog dd = (Dog)session.get(Dog.class, 1);
// System.out.println(dd.getName());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
hibernateUtil.closeSession(session);
}
}
}