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

闽公网安备 35060202000074号