把每个具体类映射到一张表是最简单的映射方式如图所示在关系数据模型中只需定义COMPANIESHOURLY_EMPLOYEES和SALARIED_EMPLOYEES表为了叙述的方便下文把HOURLY_EMPLOYEES表简称为HE表把SALARIED_EMPLOYEES表简称为SE表
HourlyEmployee类和HE表对应HourlyEmployee类本身的rate属性以及从Employee类中继承的id属性和name属性在HE表中都有对应的字段此外HourlyEmployee类继承了Employee类与Company类的关联关系与此对应在HE表中定义了参照COMPANIES表的COMPANY_ID外键
SalariedEmployee类和SE表对应SalariedEmployee类本身的salary属性以及从Employee类中继承的id属性和name属性在SE表中都有对应的字段此外SalariedEmployee类继承了Employee类与Company类的关联关系与此对应在SE表中定义了参照COMPANIES表的COMPANY_ID外键
Company类HourlyEmployee类和SalariedEmployee类都有相应的映射文件而Employee类没有相应的映射文件图显示了持久化类映射文件和数据库表之间的对应关系
图 每个具体类对应一个表
图 持久化类映射文件和数据库表之间的对应关系
如果Employee类不是抽象类即Employee类本身也能被实例化那么还需要为Employee类创建对应的EMPLOYEES表此时HE表和SE表的结构仍然和图中所示的一样这意味着在EMPLOYEES表HE表和SE表中都定义了相同的NAME字段以及参照COMPANIES表的外键COMPANY_ID另外还需为Employee类创建单独的Employeehbmxml文件
创建映射文件
从Company类到Employee类是多态关联但是由于关系数据模型没有描述Employee类和它的两个子类的继承关系因此无法映射Company类的employees集合例程是Companyhbmxml文件的代码该文件仅仅映射了Company类的id和name属性
例程 Companyhbmxml
<hibernatemapping ><class name=mypackCompany table=COMPANIES ><id name=id type=long column=ID><generator class=increment/></id><property name=name type=string column=NAME /></class></hibernatemapping>
HourlyEmployeehbmxml文件用于把HourlyEmployee类映射到HE表在这个映射文件中除了需要映射HourlyEmployee类本身的rate属性还需要映射从Employee类中继承的name属性此外还要映射从Employee类中继承的与Company类的关联关系例程是HourlyEmployeehbmxml文件的代码
例程 HourlyEmployeehbmxml
<hibernatemapping > <class name=mypackHourlyEmployee table=HOURLY_EMPLOYEES> <id name=id type=long column=ID> <generator class=increment/> </id> <property name=name type=string column=NAME /> <property name=rate column=RATE type=double /> <manytoone name=company column=COMPANY_ID class=mypackCompany /> </class> </hibernatemapping>
SalariedEmployeehbmxml文件用于把SalariedEmployee类映射到SE表在这个映射文件中除了需要映射SalariedEmployee类本身的salary属性还需要映射从Employee类中继承的name属性此外还要映射从Employee类中继承的与Company类的关联关系例程是SalariedEmployeehbmxml文件的代码
例程 SalariedEmployeehbmxml
<hibernatemapping >
<class name=mypackSalariedEmployee table=SALARIED_EMPLOYEES>
<id name=id type=long column=ID>
<generator class=increment/>
</id>
<property name=name type=string column=NAME />
<property name=salary column=SALARY type=double />
<manytoone
name=company
column=COMPANY_ID
class=mypackCompany
/>
</class>
</hibernatemapping>
由于Employee类没有相应的映射文件因此在初始化Hibernate时只需向Configuration对象中加入Company类HourlyEmployee类和SalariedEmployee类
Configuration config = new Configuration()
configaddClass(Companyclass)
addClass(HourlyEmployeeclass)
addClass(SalariedEmployeeclass)
操纵持久化对象
这种映射方式不支持多态查询在本书第章的节(多态查询)介绍了多态查询的概念对于以下查询语句
List employees=sessionfind(from Employee)
为了检索所有的Employee对象必须分别检索所有的HourlyEmployee实例和SalariedEmployee实例然后把它们合并到同一个集合中在运行Session的第一个find()方法时Hibernate执行以下select语句
select * from HOURLY_EMPLOYEES
select * from COMPANIES where ID=
从HourlyEmployee类到Company类不是多态关联在加载HourlyEmployee对象时会同时加载与它关联的Company对象
在运行Session的第二个find()方法时Hibernate执行以下select语句
select * from SALARIED_EMPLOYEES
从SalariedEmployee类到Company类不是多态关联在加载SalariedEmployee对象时会同时加载与它关联的Company对象在本书提供的测试数据中所有HourlyEmployee实例和SalariedEmployee实例都与OID为的Company对象关联由于该Company对象已经被加载到内存中所以Hibernate不再需要执行检索该对象的select语句
()运行loadCompany()方法它的代码如下
tx = sessionbeginTransaction();Company company=(Company)sessionload(Companyclassnew Long(id));List hourlyEmployees=sessionfind(from HourlyEmployee h where
panyid=+id);companygetEmployees()addAll(hourlyEmployees);List salariedEmployees=sessionfind(from SalariedEmployee s where
panyid=+id);companygetEmployees()addAll(salariedEmployees);mit();return company;
由于这种映射方式不支持多态关联因此由Session的load()方法加载的Company对象的employees集合中不包含任何Employee对象BusinessService类必须负责从数据库中检索出所有与Company对象关联的HourlyEmployee对象以及SalariedEmployee对象然后把它们加入到employees集合中
()运行saveEmployee(Employee employee)方法它的代码如下
tx = sessionbeginTransaction()
sessionsave(employee)
mit()
在test()方法中创建了一个HourlyEmployee实例然后调用saveEmployee()方法保存这个实例
Employee employee=new HourlyEmployee(Marycompany)
saveEmployee(employee)
Session的save()方法能判断employee变量实际引用的实例的类型如果employee变量引用HourlyEmployee实例就向HE表插入一条记录执行如下insert语句
insert into HOURLY_EMPLOYEES(IDNAMERATECUSTOMER_ID)
values( Mary)
如果employee变量引用SalariedEmployee实例就向SE表插入一条记录