本站首页    管理页面    写新日志    退出


«August 2025»
12
3456789
10111213141516
17181920212223
24252627282930
31


公告
 本博客在此声明所有文章均为转摘,只做资料收集使用。

我的分类(专题)

日志更新

最新评论

留言板

链接

Blog信息
blog名称:
日志总数:1304
评论数量:2242
留言数量:5
访问次数:7591492
建立时间:2006年5月29日




[Hibernate]精通Hibernate映射继承关系之六
软件技术

lhwork 发表于 2006/12/22 17:15:13

Company与Employee类之间为一对多多态关联关系,如果继承关系树的根类对应一个表,或者每个类对应一个表,那么就能映射Company类的 employees集合。本节介绍如何映射多对一多态关联。如图14-11所示,ClassD与ClassA为多对一多态关联关系。 500)this.width=500'> 图14-11 ClassD与ClassA为多对一多态关联关系ClassA、ClassB和ClassC构成了一棵继承关系树,如果继承关系树的根类对应一个表,或者每个类对应一个表,那么可以按以下方式映射ClassD的a属性: <many-to-one name="a"class="ClassA"column="A_ID"cascade="save-update" />假定与ClassD对应的表为TABLE_D,与ClassA对应的表为TABLE_A,在TABLE_D中定义了外键A_ID,它参照TABLE_A表的主键。 ClassD对象的a属性既可以引用ClassB对象,也可以引用ClassC对象,例如: tx = session.beginTransaction();ClassD d=(ClassD)session.get("ClassD",id);ClassA a=d.getA();if(a instanceof ClassB) System.out.println(((ClassB)a).getB1());if(a instanceof ClassC) System.out.println(((ClassC)a).getC1());tx.commit();以下代码在映射ClassD类的a属性时使用了延迟检索策略: <many-to-one name="a"class="ClassA"column="A_ID"lazy="true"cascade="save-update" />当Hibernate加载ClassD对象时,它的属性a引用ClassA的代理类实例,在这种情况下,如果对ClassA的代理类实例进行类型转换,会抛出ClassCastException: ClassA a=d.getA();ClassB b=(ClassB)a; //抛出ClassCastException解决以上问题的一种办法是使用Session.load()方法: ClassA a=d.getA();ClassB b=(ClassB)session.load(ClassB.class,a.getId());System.out.println(b.getB1());当执行Session的load()方法时,Hibernate并不会访问数据库,而是仅仅返回ClassB的代理类实例。这种解决办法的前提条件是必须事先知道ClassD对象实际上和ClassA的哪个子类的对象关联。 解决以上问题的另一种办法是显式使用迫切左外连接检索策略,避免Hibernate创建ClassA的代理类实例,而是直接创建ClassA的子类的实例: tx = session.beginTransaction();ClassD d=(ClassD)session.createCriteria(ClassD.class) .add(Expression.eq("id",id)) .setFetchMode("a",FetchMode.EAGER) .uniqueResult();ClassA a=d.getA();if(a instanceof ClassB) System.out.println(((ClassB)a).getB1());if(a instanceof ClassC) System.out.println(((ClassC)a).getC1());tx.commit();如 果继承关系树的具体类对应一个表,为了表达ClassD与ClassA的多态关联,需要在TABLE_D中定义两个字段:A_ID和A_TYPE, A_TYPE字段表示子类的类型,A_ID参照在子类对应的表中的主键。图14-12显示了表TABLE_D、TABLE_B和TABLE_C的结构。 500)this.width=500'> 图14-12 表TABLE_D、TABLE_B和TABLE_C的结构由于关系数据模型不允许一个表的外键同时参照 两个表的主键,因此无法对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应用的编程提供方便。


阅读全文(1631) | 回复(0) | 编辑 | 精华
 



发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)



站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.270 second(s), page refreshed 144774008 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号