| |
由于关系数据模型不允许一个表的外键同时参照两个表的主键,因此无法对table_d表的a_id字段定义外键参照约束,而应该通过其他方式,如触发器,来保证a_id字段的参照完整性。由于table_d表的a_id字段既可能参照table_b表的id主键,也可能参照table_c表的id主键,要求table_b表和talbe_c表的id主键具有相同的sql类型。 在classd.hbm.xml文件中,用元素来映射classd的a属性: <any name="a" meta-type="string" id-type="long" cascade="save-update"> <meta-value value="b" class="classb" /> <meta-value value="c" class="classc" /> <column name="a_type" /> <column name="a_id" /> </any> 元素的meta-type属性指定table_d中a_type字段的类型,id-type属性指定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 rate,company company) { super(name,company); this.rate=rate; } /** 默认构造方法*/ public hourlyemployee() {} …… } hibernate只会访问持久化类的默认构造方法,永远不会访问其他形式的构造方法。提供以上形式的完整构造方法,主要是为java应用的编程提供方便。
|
|