精通Hibernate映射继承关系之二
2007-12-23 12:33:42 来源:WEB开发网把每个具体类映射到一张表是最简单的映射方式。如图14-2所示,在关系数据模型中只需定义COMPANIES、HOURLY_EMPLOYEES和SALARIED_EMPLOYEES表。为了叙述的方便,下文把HOURLY_EMPLOYEES表简称为HE表,把SALARIED_EMPLOYEES表简称为SE表。
HourlyEmployee类和HE表对应,HourlyEmployee类本身的rate属性,以及从Employee类中继承的id属性和name属性,在HE表中都有对应的字段。此外,HourlyEmployee类继承了Employee类与Company类的关联关系,与此对应,在HE表中定义了参照COMPANIES表的COMPANY_ID外键。
SalariedEmployee类和SE表对应,SalariedEmployee类本身的salary属性,以及从Employee类中继承的id属性和name属性,在SE表中都有对应的字段。此外,SalariedEmployee类继承了Employee类与Company类的关联关系,与此对应,在SE表中定义了参照COMPANIES表的COMPANY_ID外键。
Company类、HourlyEmployee类和SalariedEmployee类都有相应的映射文件,而Employee类没有相应的映射文件。图14-3显示了持久化类、映射文件和数据库表之间的对应关系。
14.1.1 创建映射文件
从Company类到Employee类是多态关联,但是由于关系数据模型没有描述Employee类和它的两个子类的继承关系,因此无法映射Company类的employees集合。例程14-1是Company.hbm.xml文件的代码,该文件仅仅映射了Company类的id和name属性。
例程14-1 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" /> </class> </hibernate-mapping>
HourlyEmployee.hbm.xml文件用于把HourlyEmployee类映射到HE表,在这个映射文件中,除了需要映射HourlyEmployee类本身的rate属性,还需要映射从Employee类中继承的name属性,此外还要映射从Employee类中继承的与Company类的关联关系。例程14-2是HourlyEmployee.hbm.xml文件的代码。
例程14-2 HourlyEmployee.hbm.xml
<hibernate-mapping > <class name="mypack.HourlyEmployee" table="HOURLY_EMPLOYEES"> <id name="id" type="long" column="ID"> <generator class="increment"/> </id> <property name="name" type="string" column="NAME" /> <property name="rate" column="RATE" type="double" /> <many-to-one name="company" column="COMPANY_ID" class="mypack.Company" /> </class> </hibernate-mapping>
SalariedEmployee.hbm.xml文件用于把SalariedEmployee类映射到SE表,在这个映射文件中,除了需要映射SalariedEmployee类本身的salary属性,还需要映射从Employee类中继承的name属性,此外还要映射从Employee类中继承的与Company类的关联关系。例程14-3是SalariedEmployee.hbm.xml文件的代码。
例程14-3 SalariedEmployee.hbm.xml
由于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");
在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;
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表插入一条记录。
(出处:http://www.cncms.com)
- ››Hibernate高级应用:性能优化策略
- ››hibernate 多对多关系详解(包括中间表,一对多字表...
- ››Hibernate实现mysql数据库limit查询方法
- ››精通Photoshop之通道详解
- ››Hibernate 之父:是时候升级到Java EE 6了
- ››Hibernate查询
- ››Hibernate和iBATIS比较(摘自网络)
- ››Hibernate使用Projections进行聚合操作
- ››hibernate中java.util.Date类型映射
- ››hibernate中update与saveOrUpdate的区别
- ››精通 Grails: 使用 Grails 进行单元测试(单元测试...
- ››Hibernate各种映射关系总结
更多精彩
赞助商链接