本站首页    管理页面    写新日志    退出


«August 2025»
12
3456789
10111213141516
17181920212223
24252627282930
31


公告
 本博客在此声明所有文章均为转摘,只做资料收集使用。

我的分类(专题)

日志更新

最新评论

留言板

链接

Blog信息
blog名称:
日志总数:1304
评论数量:2242
留言数量:5
访问次数:7591393
建立时间:2006年5月29日




[Hibernate]精通Hibernate映射继承关系之二
软件技术

lhwork 发表于 2006/12/22 17:11:17

把每个具体类映射到一张表是最简单的映射方式。如图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显示了持久化类、映射文件和数据库表之间的对应关系。 500)this.width=500'> 图14-2 每个具体类对应一个表 500)this.width=500'> 图14-3 持久化类、映射文件和数据库表之间的对应关系 如果Employee类不是抽象类,即Employee类本身也能被实例化,那么还需要为Employee类创建对 应的EMPLOYEES表,此时HE表和SE表的结构仍然和图14-2中所示的一样。这意味着在EMPLOYEES表、HE表和SE表中都定义了相同的 NAME字段以及参照COMPANIES表的外键COMPANY_ID。另外,还需为Employee类创建单独的Employee.hbm.xml文 件。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 <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());}elseSystem.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表插入一条记录。


阅读全文(2084) | 回复(0) | 编辑 | 精华
 



发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)



站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.313 second(s), page refreshed 144771629 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号