| |
company与employee类之间为一对多多态关联关系,如果继承关系树的根类对应一个表,或者每个类对应一个表,那么就能映射company类的employees集合。本节介绍如何映射多对一多态关联。如图14-11所示,classd与classa为多对一多态关联关系。  图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的结构。  图14-12 表table_d、table_b和table_c的结构
|
|