| |
在这种映射方式下,继承关系树的每个类以及接口都对应一个表。在本例中,需要创建employees、he和se表。 如图14-6所示,employees表仅包含和employee类的属性对应的字段,he表仅包含和hourlyemployee类的属性对应的字段,se表仅包含和salariedemployee类的属性对应的字段。此外,he表和se表都以employee_id字段作为主键,该字段还同时作为外键参照employees表。  图14-6 继承关系树的每个类对应一个表  图14-7 持久化类、映射文件和数据库表之间的对应关系 14.3.1 创建映射文件 从company类到employee类是多态关联,由于关系数据模型描述了employee类和它的两个子类的继承关系,因此可以映射company类的employees集合。例程14-7是company.hbm.xml文件的代码,该文件不仅映射了company类的id和name属性,还映射了它的employees集合。 例程14-7 company.hbm.xml <hibernate-mapping > <class name="mypack.company" table="companies" > <id name="id" type="long" column="id"> <generator class="increment"/> </id> <property name="name" type="string" column="name" /> <set name="employees" inverse="true" lazy="true" > <key column="company_id" /> <one-to-many class="mypack.employee" /> </set> </class> </hibernate-mapping> employee.hbm.xml文件用于把employee类映射到employees表,在这个映射文件中,除了需要映射employee类本身的属性,还需要在元素中映射两个子类的属性。例程14-8是employee.hbm.xml文件的代码。 例程14-8 employee.hbm.xml <hibernate-mapping > <class name="mypack.employee" table="employees"> <id name="id" type="long" column="id"> <generator class="increment"/> </id> <property name="name" type="string" column="name" /> <many-to-one name="company" column="company_id" class="mypack.company" /> <joined-subclass name="mypack.hourlyemployee" table="hourly_employees" > <key column="employee_id" /> <property name="rate" column="rate" type="double" /> </joined-subclass> <joined-subclass name="mypack.salariedemployee" table="salaried_employees" > <key column="employee_id" /> <property name="salary" column="salary" type="double" /> </joined-subclass> </class> </hibernate-mapping> 在employee.hbm.xml文件中,两个元素用于映射hourlyemployee类和salariedemployee类,元素的子元素指定he表和se表中既作为主键又作为外键的employee_id字段。 由于hourlyemployee类和salariedemployee类没有单独的映射文件,因此在初始化hibernate时,只需向configuration对象中加入company类和employee类: configuration config = new configuration(); config.addclass(company.class) .addclass(employee.class); 也可以在单独的映射文件中配置或元素,但此时必须显式设定它们的extends属性。例如可以在单独的hourlyemployee.hbm.xml文件中映射hourlyemployee类: <hibernate-mapping > <joined-subclass name="mypack.hourlyemployee" table="hourly_employees" extends="mypack.employee" > …… </joined-class> <hibernate-mapping > 由于hourlyemployee类的映射代码不位于employee.hbm.xml文件中,因此在初始化hibernate时,不仅需要向configuration对象中加入company类和employee类,还需要加入hourlyemployee类,并且必须先加入employee父类,再加入hourlyemployee子类: configuration config = new configuration(); config.addclass(company.class) .addclass(employee.class) .addclass(hourlyemployee.class); 如果颠倒加入employee类和hourlyemployee子类的顺序,hibernate在执行addclass()方法时会抛出hibernatemappingexception。 14.3.2 操纵持久化对象 这种映射方式支持多态查询,对于以下查询语句: list employees=session.find("from employee"); hibernate会检索出所有的hourlyemployee对象和salariedemployee对象。此外,也可以单独查询employee类的两个子类的实例,例如: list hourlyemployees=session.find("from hourlyemployee"); 本节的范例程序位于配套光盘的sourcecode/chapter14/14.3目录下,运行该程序前,需要在sampledb数据库中手工创建companies表、employees表、he表和se表,然后加入测试数据,相关的sql脚本文件为/14.3/schema/sampledb.sql。 在dos命令行下进入chapter14根目录,然后输入命令: ant -file build3.xml run 就会运行businessservice类。businessservice的main()方法调用test()方法,test()方法依次调用以下方法: findallhourlyemployees():检索数据库中所有的hourlyemployee对象。 findallemployees():检索数据库中所有的employee对象。 loadcompany():加载一个company对象。 saveemployee():保存一个employee对象。 (1)运行findallhourlyemployees()方法,它的代码如下: tx = session.begintransaction(); list results=session.find("from hourlyemployee"); tx.commit(); return results; 在运行session的find()方法时,hibernate执行以下select语句: select * from hourly_employees he inner join employees e on he.employee_id=e.id; select * from companies where id=1; hibernate通过he表与employees表的内连接获得hourlyemployee对象的所有属性值,此外,在加载hourlyemployee对象时,还会同时加载与它关联的company对象。 (2)运行findallemployees()方法,它的代码如下: tx = session.begintransaction(); list results=session.find("from employee"); tx.commit(); return results; 在运行session的find()方法时,hibernate执行以下select语句: select * from employees e left outer join hourly_employees he on e.id=he.employee_id left outer join salaried_employees se on e.id=se.employee_id; select * from companies where id=1; hibernate把employees表与he表以及se表进行左外连接,从而获得hourlyemployee对象和salariedemployee对象的所有属性值。在这种映射方式下,hibernate支持多态查询,对于以上查询语句获得的查询结果,如果he表的employee_id字段不为null,就创建houlyemployee实例,如果se表的employee_id字段不为null,就创建salariedemployee实例,这些实例所关联的company对象也被加载。(3)运行loadcompany()方法,它的代码如下: tx = session.begintransaction(); company company=(company)session.load(company.class,new long(id)); hibernate.initialize(company.getemployees()); tx.commit(); 这种映射方式支持多态关联。如果在company.hbm.xml文件中对employees集合设置了立即检索策略,那么session的load()方法加载的company对象的employees集合中包含所有关联的employee对象。由于本书提供的company.hbm.xml文件对employees集合设置了延迟检索策略,因此以上程序代码还通过hibernate类的静态initialize()方法来显式初始化employees集合。 (4)运行saveemployee(employee employee)方法,它的代码如下: tx = session.begintransaction(); session.save(employee); tx.commit(); 在test()方法中,创建了一个hourlyemployee实例,然后调用saveemployee()方法保存这个实例: employee employee=new hourlyemployee("mary",300,company); saveemployee(employee); session的save()方法能判断employee变量实际引用的实例的类型,如果employee变量引用hourlyemployee实例,就执行如下insert语句: insert into employees (id,name, company_id) values (5, 'mary', 1); insert into hourly_employees (employee_id ,rate) values (5, 300); 可见,每保存一个hourlyemployee对象,需要分别向employees表和he表插入一条记录,employees表的记录和he表的记录共享同一个主键。
|
|