精通Hibernate之映射继承关系三

本文探讨了在使用Hibernate框架进行对象关系映射时遇到的多态性问题,并提供了具体的解决方案,包括如何通过手动方式实现多态查询及关联。
  <hibernate-mapping >   <class name="mypack.SalariedEmployee" table="SALARIED_EMPLOYEES">   <id name="id" type="long" column="ID">   <generator class="increment"/>   </id>      <property name="name" type="string" column="NAME" />   <property name="salary" column="SALARY" type="double" />      <many-to-one   name="company"   column="COMPANY_ID"   class="mypack.Company"   />   </class>   </hibernate-mapping>      由于Employee类没有相应的映射文件,因此在初始化Hibernate时,只需向Configuration对象中加入Company类、HourlyEmployee类和SalariedEmployee类:      Configuration config = new Configuration();   config.addClass(Company.class)   .addClass(HourlyEmployee.class)   .addClass(SalariedEmployee.class);      14.1.2 操纵持久化对象      这种映射方式不支持多态查询,在本书第11章的11.1.6节(多态查询)介绍了多态查询的概念。对于以下查询语句:      List employees=session.find("from Employee");      如果Employee类是抽象类,那么Hibernate会抛出异常。如果Employee类是具体类,那么Hibernate仅仅查询EMPLOYEES表,检索出Employee类本身的实例,但不会检索出它的两个子类的实例。本节的范例程序位于配套光盘的sourcecode/chapter14/14.1目录下,运行该程序前,需要在SAMPLEDB数据库中手工创建COMPANIES表、HE表和SE表,然后加入测试数据,相关的SQL脚本文件为/14.1/schema/sampledb.sql。      在chapter14目录下有四个ANT的工程文件,分别为build1.xml、build2.xml、build3.xml和build4.xml,它们的区别在于文件开头设置的路径不一样,例如在build1.xml文件中设置了以下路径:      <property name="source.root" value="14.1/src"/>   <property name="class.root" value="14.1/classes"/>   <property name="lib.dir" value="lib"/>   <property name="schema.dir" value="14.1/schema"/>      在DOS命令行下进入chapter14根目录,然后输入命令:      ant -file build1.xml run      就会运行BusinessService类。ANT命令的-file选项用于显式指定工程文件。BusinessService类用于演示操纵Employee类的对象的方法,例程14-4是它的源程序。      例程14-4 BusinessService.java      public class BusinessService{   public static SessionFactory sessionFactory;   static{   try{   Configuration config = new Configuration();   config.addClass(Company.class)   .addClass(HourlyEmployee.class)   .addClass(SalariedEmployee.class);   sessionFactory = config.buildSessionFactory();   }catch(Exception e){e.printStackTrace();}   }      public void saveEmployee(Employee employee) throws Exception{……}   public List findAllEmployees() throws Exception{……}   public Company loadCompany(long id) throws Exception{……}      public void test() throws Exception{   List employees=findAllEmployees();   printAllEmployees(employees.iterator());      Company company=loadCompany(1);   printAllEmployees(company.getEmployees().iterator());      Employee employee=new HourlyEmployee("Mary",300,company);   saveEmployee(employee);      }      private void printAllEmployees(Iterator it){   while(it.hasNext()){   Employee e=(Employee)it.next();   if(e instanceof HourlyEmployee){   System.out.println(((HourlyEmployee)e).getRate());   }else   System.out.println(((SalariedEmployee)e).getSalary());   }   }   public static void main(String args[]) throws Exception {   new BusinessService().test();   sessionFactory.close();   }   }   BusinessService的main()方法调用test()方法,test()方法依次调用以下方法。   findAllEmployees():检索数据库中所有的Employee对象。   loadCompany():加载一个Company对象。   saveEmployee():保存一个Employee对象。      (1)运行findAllEmployees()方法,它的代码如下:      List results=new ArrayList();   tx = session.beginTransaction();   List hourlyEmployees=session.find("from HourlyEmployee");   results.addAll(hourlyEmployees);      List salariedEmployees=session.find("from SalariedEmployee");   results.addAll(salariedEmployees);      tx.commit();   return results;      为了检索所有的Employee对象,必须分别检索所有的HourlyEmployee实例和SalariedEmployee实例,然后把它们合并到同一个集合中。在运行Session的第一个find()方法时,Hibernate执行以下select语句:      select * from HOURLY_EMPLOYEES;   select * from COMPANIES where ID=1;      从HourlyEmployee类到Company类不是多态关联,在加载HourlyEmployee对象时,会同时加载与它关联的Company对象。      在运行Session的第二个find()方法时,Hibernate执行以下select语句:      select * from SALARIED_EMPLOYEES;      从SalariedEmployee类到Company类不是多态关联,在加载SalariedEmployee对象时,会同时加载与它关联的Company对象。在本书提供的测试数据中,所有HourlyEmployee实例和SalariedEmployee实例都与OID为1的Company对象关联,由于该Company对象已经被加载到内存中,所以Hibernate不再需要执行检索该对象的select语句。      (2)运行loadCompany()方法,它的代码如下:      tx = session.beginTransaction();   Company company=(Company)session.load(Company.class,new Long(id));      List hourlyEmployees=session.find("from HourlyEmployee h where h.company.id="+id);   company.getEmployees().addAll(hourlyEmployees);      List salariedEmployees=session.find("from SalariedEmployee s where s.company.id="+id);   company.getEmployees().addAll(salariedEmployees);      tx.commit();   return company;      由于这种映射方式不支持多态关联,因此由Session的load()方法加载的Company对象的employees集合中不包含任何Employee对象。BusinessService类必须负责从数据库中检索出所有与Company对象关联的HourlyEmployee对象以及SalariedEmployee对象,然后把它们加入到employees集合中。      (3)运行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实例,就向HE表插入一条记录,执行如下insert语句:      insert into HOURLY_EMPLOYEES(ID,NAME,RATE,CUSTOMER_ID)   values(3, 'Mary',300,1);      如果employee变量引用SalariedEmployee实例,就向SE表插入一条记录。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值