hibernate的继承映射
《一》一张表映射一棵继承树
使用discriminator(鉴别标志)
类Worker和Farmer都继承自Person
类Person的源代码如下:
package hibernate.extend;
public class Person {
private int id;
private String name;
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
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;
}
}
类Worker的源代码如下:
package hibernate.extend;
public class Worker extends Person{
public int getWork_year() {
return work_year;
}
public void setWork_year(int work_year) {
this.work_year = work_year;
}
private int work_year;//工人的工龄
}
类Farmer的源代码如下:
package hibernate.extend;
public class Farmer extends Person {
private String farm_name;//农民的农场名
public String getFarm_name() {
return farm_name;
}
public void setFarm_name(String farm_name) {
this.farm_name = farm_name;
}
}
只有一个映射文件person.hbm.xml
<?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 package="hibernate.extend">
<class name="Person" table="person" discriminator-value="0" >
<id name="id">
<generator class="native"/>
</id>
<discriminator column="type" type="int"/> //通过discriminator节点,我们声明了用做子类辨别标识的字段名
<property name="name"/>
<property name="age"/>
<subclass name="Worker" discriminator-value="1" >
<property name="work_year"/>
</subclass>
<subclass name="Farmer" discriminator-value="2" >
<property name="farm_name"/>
</subclass>
</class>
</hibernate-mapping>
测试代码:
static void add(){
Person p = new Person();
p.setName("person");
p.setAge(22);
Worker worker = new Worker();
worker.setName("worker");
worker.setAge(30);
worker.setWork_year(11);
Farmer farmer = new Farmer();
farmer.setName("farmer");
farmer.setAge(31);
farmer.setFarm_name("little candy");
Session s = HibernateUtil.getSession();
Transaction tx = s.beginTransaction();
s.save(p);
s.save(worker);
s.save(farmer);
tx.commit();
}
执行报出异常:
org.hibernate.DuplicateMappingException: duplicate import: Person refers to both hibernate.extend.Person and hibernatetest01.Person (try using auto-import="false")
检查后发现,在hibernaqte.cfg.xml配置文件中,我在以前写一对一关系映射时,曾经用到过Person类。
<mapping resource="hibernatetest01/person.hbm.xml"/>
<mapping resource="hibernate/extend/person.hbm.xml"/>
异常也显示说我重复映射。并提示我使用auto-import属性。
修改映射文件:
<?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 package="hibernate.extend" auto-import="false" >
<class name="Person" table="person" discriminator-value="0" >
<id name="id">
<generator class="native"/>
</id>
<discriminator column="type" type="int"/> //这一列对对象模型没有作用,是hibernate用来区分具体的子类用的
<property name="name"/>
<property name="age"/>
<subclass name="Worker" discriminator-value="1">
<property name="work_year"/>
</subclass>
<subclass name="Farmer" discriminator-value="2">
<property name="farm_name"/>
</subclass>
</class>
</hibernate-mapping>
修改后,问题得到解决。执行以上程序代码,显示的sql语句为:
Hibernate: insert into person (name, age, work_year, type) values (?, ?, ?, 1)
Hibernate: insert into person (name, age, farm_name, type) values (?, ?, ?, 2)
查看数据库的表结构为:
+----+------+--------+------+----------------+--------------+
| id | type | name | age | work_year | farm_name|
+----+------+----------+-----+--------------+--------------+
| 1 | 0 | person | 22 | NULL | NULL |
| 2 | 1 | worker | 30 | 11 | NULL |
| 3 | 2 | farmer | 31 | NULL | little candy|
+----+------+----------+------+---------------+-------------+
由上面可见:work_year和farm_name属性必须是可以为null的。不然第一条插入语句就会出现问题。这也是这种方法的一种局限。表中有冗余字段。表结构不是很合理。同时,在类体系结构上增加新的子类时,要对数据库表的结构做修改,也使得不是很方便。
这种方案,由于对类体系的操作归结为对一张表的操作,在性能上有一定的优势。
充:
auto-import (可选 - 默认为 true): 指定是否我们可以在查询语言中使用非全限定的类名(仅限于本映射文件中的类)。
假若你有两个持久化类,它们的非全限定名是一样的(就是在不同的包里面),你应该设置auto-import="false"。假若说你把一个“import过”的名字同时对应两个类, Hibernate会抛出一个异常。