现在有四个类Company、Employee、SalaryEmployee、HourlyEmployee,其中Employee是SalaryEmployee、HourlyEmployee的父类
类的实现代码如下:
public class Company implements java.io.Serializable {
// Fields
private Integer id;
private String name;
private Set Employees = new HashSet(0);
}
public class Employee implements java.io.Serializable {
// Fields
private Integer id;
private String name;
private Company company;
}
public class HourlyEmployee extends Employee implements java.io.Serializable {
// Fields
private Double rate;
}
public class SalaryEmployee extendsEmployee implements java.io.Serializable {
// Fields
private Double salary;
}
这四个类都省略了getter/setter方法,并且都是用Hibernate反向机制自动生成的。
该种实现Hibernate继承映射策略——每个具体对应一张表,上述的具体类就是HourlyEmployee和SalaryEmployee
首先设计下数据库,具体如下图:
company表
hourly_employee表
salary_employee表
hourly_employee和salary_employee表中的字段company_id为外键,参照company表中的id
配置company.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">
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
<class name="com.xkey.hibernate.bean.Company" table="company" catalog="hibernate">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="identity" />
</id>
<property name="name" type="java.lang.String">
<column name="name" length="128" not-null="true" />
</property>
<set name="Employee1s" inverse="true" cascade="all" lazy="true">
<key>
<column name="company_id" not-null="true" />
</key>
<one-to-many class="com.xkey.hibernate.bean.Employee1" />
</set>
</class>
</hibernate-mapping>
配置Employee1.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">
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
<class name="com.xkey.hibernate.bean.Employee1">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="increment" />
</id>
<property name="name" type="java.lang.String">
<column name="name" length="128" not-null="true" />
</property>
<many-to-one name="company" class="com.xkey.hibernate.bean.Company"
fetch="select">
<column name="company_id" not-null="true" />
</many-to-one>
<union-subclass name="com.xkey.hibernate.bean.HourlyEmployee1"
table="hourly_employee1" extends="com.xkey.hibernate.bean.Employee1">
<property name="rate" type="java.lang.Double">
<column name="rate" precision="10" scale="5"></column>
</property>
</union-subclass>
<union-subclass name="com.xkey.hibernate.bean.SalaryEmployee1"
table="salary_employee1" extends="com.xkey.hibernate.bean.Employee1">
<property name="salary" type="java.lang.Double">
<column name="salary" precision="10" scale="5"></column>
</property>
</union-subclass>
</class>
</hibernate-mapping>
Employee1.hbm.xml中hourly_employee表和salary_employee表拥有的公共字段使用<property>,外键使用<many-to-one>,对于每个表特定的字段就使用<union-subclass>
具体就看上面的配置文件就可以了。
这里需要注意的是:使用<union-subclass>那么generator就不能使用class="identity",否则会报错:Cannot use identity column key generation with <union-subclass> mapping
还有一点就是<class name="com.xkey.hibernate.bean.Employee1">如果添加abstract属性的话,如果abstract="true"那么将不会生成表结构,如果abstract="false"那么将不会插入数据。个人觉得这个属性还是不要加的好。
在具体insert数据的时候会出现如下问题:
Company company = new Company("xkey",new HashSet());
HourlyEmployee1 employee1 = new HourlyEmployee1("xukai",company,12.5);
SalaryEmployee1 employee2 = new SalaryEmployee1("color",company,10000.0);
company.getEmployee1s().add(employee1);
company.getEmployee1s().add(employee2);
CompanyDAO dao = new CompanyDAO();
dao.save(company);
上面这段代码就是company、hourly_employee、salary_employee个插入一条数据,但是都是参照同一个company,这里在insert后会发现hourly_employee、salary_employee表中的主键id是不连续,具体是什么原因就需要去问Hibernate了,不用说也应该知道,问题肯定在session那里。
下图是我连续执行两次上述代码的结果
由于只有EmployeeDAO这一个DAO层访问数据库的方法,所以在查询的时候会很蛋疼,如果按照id来查询,那么查询出来的值究竟是hourly_employee表的数据还是salary_employee表呢,解决这个就需要调用返回值的类型来判断下。
综上所述,此种实现继承映射的方法个人觉得很蛋疼,还不如hourly_employee、salary_employee表个搞一个hbm.xml文件呢,这样对数据库的操作都将很方便,并且数据库存储的开销也和上面的方法相同,所以这种解决映射问题的方法不可取,大家就使用平常的方法就可以了。
还有其他两种解决映射问题的方法,将在后面介绍。
上面都是本人自己的见解,刚刚接触Hibernate,如果有说的不对的地方还望大家指正。