由于关系数据模型不允许一个表的外键同时参照两个表的主键因此无法对TABLE_D表的A_ID字段定义外键参照约束而应该通过其他方式如触发器来保证A_ID字段的参照完整性由于TABLE_D表的A_ID字段既可能参照TABLE_B表的ID主键也可能参照TABLE_C表的ID主键要求TABLE_B表和TALBE_C表的ID主键具有相同的SQL类型
在ClassDhbmxml文件中用元素来映射ClassD的a属性
<any name=a
metatype=string
idtype=long
cascade=saveupdate>
<metavalue value=B class=ClassB />
<metavalue value=C class=ClassC />
<column name=A_TYPE />
<column name=A_ID />
</any>
元素的metatype属性指定TABLE_D中A_TYPE字段的类型idtype属性指定TABLE_D中A_ID字段的类型子元素设定A_TYPE字段的可选值在本例中如果A_TYPE字段取值为B表示为ClassB的对象A_ID字段参照TABLE_B表中的ID主键如果A_TYPE字段取值为C表示为ClassC的对象A_ID字段参照TABLE_C表中的ID主键子元素指定TABLE_D表中的A_TYPE字段和A_ID字段必须先指定A_TYPE字段再指定A_ID字段
小结
本章介绍了映射继承关系的三种方式
继承关系树的每个具体类对应一个表在具体类对应的表中不仅包含和具体类的属性对应的字段还包含和具体类的父类的属性对应的字段这种映射方式不支持多态关联和多态查询
继承关系树的根类对应一个表在根类对应的表中不仅包含和根类的属性对应的字段还包含和所有子类的属性对应的字段
这种映射方式支持多态关联和多态查询并且能获得最佳查询性能缺点是需要对关系数据模型进行非常规设计在数据库表中加入额外的区分各个子类的字段此外不能为所有子类的属性对应的字段定义not null约束
继承关系树的每个类对应一个表在每个类对应的表中只需包含和这个类本身的属性对应的字段子类对应的表参照父类对应的表
这种映射方式支持多态关联和多态查询而且符合关系数据模型的常规设计规则缺点是它的查询性能不如第二种映射方式在这种映射方式下必须通过表的内连接或左外连接来实现多态查询和多态关联
在默认情况下对于简单的继承关系树可以采用根类对应一个表的映射方式如果必须保证关系数据模型的数据完整性可以采用每个类对应一个表的映射方式对于复杂的继承关系树可以将它分解为几棵子树对每棵子树采用不同的映射方式
当然在设计域模型时应该尽量避免设计过分复杂的继承关系这不仅会增加把域模型映射到关系数据模型的难度而且也会增加在Java程序代码中操纵持久化对象的复杂度
对于不同的映射方式必须创建不同的关系数据模型和映射文件但是域模型是一样的域模型中的持久化类的实现也都一样
只要具备Java编程基础知识就能创建具有继承关系的持久化类因此本章没有详细介绍这些持久化类的创建过程在此仅提醒一点子类的完整构造方法不仅负责初始化子类本身的属性还应该负责初始化从父类中继承的属性例如以下是HourlyEmployee类的构造方法
public class HourlyEmployee extends Employee{
private double rate;
/** 完整构造方法*/
public HourlyEmployee(String name double rateCompany company) {
super(namecompany);
thisrate=rate;
}
/** 默认构造方法*/
public HourlyEmployee() {}
……
}
Hibernate只会访问持久化类的默认构造方法永远不会访问其他形式的构造方法提供以上形式的完整构造方法主要是为Java应用的编程提供方便