`
dev_liu
  • 浏览: 111668 次
  • 性别: Icon_minigender_1
  • 来自: 成都
最近访客 更多访客>>
社区版块
存档分类
最新评论

Hibernate映射继承关系的三种方式(1)zt

阅读更多
Company类和Employee类之间为一对多的双向关联关系(假定不允许雇员同时在多个公司兼职),Employee为抽象类因此不能被实例化,它有两个具体的子类;HourlyEmployee类和SalariedEmployee类。

由于Java只允许一个类最多有一个直接的父类,因此Employ类、HourlyEmployee类和SalariedEmployee类构成了一棵继承关系树。

 

        

          图 继承关系树

多态在图中的表现:

List employees=businessService.findAllEmployees();

Iterator it=employees.iterator();

while(it.hasNext()){

  Employee e=(Employee)it.next();

  if(e instanceof HourlyEmployee){

    System.out.println(e.getName()+""+((HourlyEmployee)e).getRate());

  }else{

    System.out.println(e.getName()+""+((SalariedEmployee)e).getSalary());

  }

第一种方式:是将每个具体的类映射为一张表也是最简单的。

 

继承关系树的每个具体类对应一张表:这种映射方式关系数据模型完全不支持域模型中的继承关系和多态。

 

            

              图 1 每个具体类对应的表

    

            图 2 持久化类、映射文件和数据表之间的对应关系

 

     如果Employee类不是抽象类(这里Employee类被设计成了抽象类),即Employee类也能被实例化,那么还需要为Employee类创建对应的Employees表,此时HOURLY_EMPLOYEES表和SALARIED_EMPLOYEES表结构仍然和图1相同,只不过多了一个EMPLOYEES表。

 

                图 3 每个具体类对应的表

 

另外,还需要为Employee类创建单独的Employee.hbm.xml文件。

在这里我只讨论设计成常用的抽象类的模式。

 

    从Company类到Employee类是多态关联,但是由于关系数据<nobr>模型</nobr>没有描述Employee类和它的两个子类的继承关系,因此无法映射Company类的employees集合。Company.hbm.xml文件的代码,该文件仅仅映射了Company类的id和name属性。

例程:Company.hbm.xml

 

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<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类的关联关系。

 

例程:HourlyEmployee.hbm.xml

 

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<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<nobr>属性</nobr>,还需要映射从Employee类中继承的name属性,此外还需要映射从Employee类中继承的与Company类的关联关系。

例程:SalariedEmployee.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<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);

 

这中方式不支持多态查询,所以

 

List employees=session.find("from Employee");

 

会抛出异常。因为Employee是抽象类,但如果Employee类是具体类的话也只会查询出EMPLOYEE表的记录不会检索出它的两个子类的实例。

 

源码如下:

hibernate.properties

 

hibernate.dialect=net.sf.hibernate.dialect.MySQLDialect
hibernate.connection.driver_class=com.mysql.jdbc.Driver
hibernate.connection.url=jdbc:mysql://localhost:3306/SAMPLEDB
hibernate.connection.username=root
hibernate.connection.password=1234
hibernate.show_sql=true

BusinessService.java

 

package mypack;

import net.sf.hibernate.*;
import net.sf.hibernate.cfg.Configuration;
import java.util.*;
import java.sql.*;

public class BusinessService{
  public static SessionFactory sessionFactory;
  static{
     try{
      // Create a configuration based on the properties file we've put
       Configuration config = new Configuration();
       config.addClass(Company.class)
             .addClass(HourlyEmployee.class)
             .addClass(SalariedEmployee.class);
      // Get the session factory we can use for persistence
      sessionFactory = config.buildSessionFactory();
    }catch(Exception e){e.printStackTrace();}

  }

  public void saveEmployee(Employee employee) throws Exception{
      Session session = sessionFactory.openSession();
      Transaction tx = null;
      List results=new ArrayList();
      try {
       tx = session.beginTransaction();
       session.save(employee);
       tx.commit();
    }catch (Exception e) {
      if (tx != null) {
        // Something went wrong; discard all partial changes
        tx.rollback();
      }
      throw e;
    } finally {
      // No matter what, close the session
      session.close();
    }
  }


  public List findAllEmployees() throws Exception{
      Session session = sessionFactory.openSession();
      Transaction tx = null;

      try {
       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;
    }catch (Exception e) {
      if (tx != null) {
        // Something went wrong; discard all partial changes
        tx.rollback();
      }
      throw e;
    } finally {
      // No matter what, close the session
      session.close();
    }
  }

  public Company loadCompany(long id) throws Exception{
      Session session = sessionFactory.openSession();
      Transaction tx = null;
      try {
       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;
    }catch (Exception e) {
      if (tx != null) {
        // Something went wrong; discard all partial changes
        tx.rollback();
      }
      throw e;
    } finally {
      // No matter what, close the session
      session.close();
    }
  }

   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();
  }
}

Company.java

 

package mypack;

import java.io.Serializable;
import java.util.Set;
import java.util.HashSet;

public class Company implements Serializable {

    private Long id;
    private String name;
    private Set employees=new HashSet();

    /** full constructor */
    public Company(String name, Set employees) {
        this.name = name;
        this.employees = employees;
    }

    /** default constructor */
    public Company() {
    }

    /** minimal constructor */
    public Company(Set employees) {
        this.employees = employees;
    }

    public Long getId() {
        return this.id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set getEmployees() {
        return this.employees;
    }

    public void setEmployees(Set employees) {
        this.employees = employees;
    }
}

Company.hbm.xml

 

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<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>

 

Employee.java

 

package mypack;

import java.io.Serializable;

abstract public class Employee implements Serializable {

    private Long id;
    private String name;
    private Company company;

    /** full constructor */
    public Employee(String name,Company company) {
        this.name = name;
        this.company = company;
    }

    /** default constructor */
    public Employee() {
    }

    public Long getId() {
        return this.id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Company getCompany() {
        return this.company;
    }

    public void setCompany(Company company) {
        this.company = company;
    }
}

HourlyEmployee.java

 

package mypack;

import java.io.Serializable;

public class HourlyEmployee extends Employee{

    private double rate;

    /** full constructor */
    public HourlyEmployee(String name, double rate,Company company) {
        super(name,company);
        this.rate=rate;
    }

    /** default constructor */
    public HourlyEmployee() {
    }

    public double getRate() {
        return this.rate;
    }

    public void setRate(double rate) {
        this.rate = rate;
    }
   
}

HourlyEmployee.hbm.xml

 

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<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.java

 

package mypack;

import java.io.Serializable;

public class SalariedEmployee extends Employee {

    private double salary;

    /** full constructor */
    public SalariedEmployee(String name, double salary,Company company) {
        super(name,company);
        this.salary=salary;
       
    }

    /** default constructor */
    public SalariedEmployee() {
    }

   public double getSalary() {
        return this.salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }
}

SalariedEmployee.hbm.xml

 

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<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>

 

sampledb.sql

 

drop database if exists SAMPLEDB;
create database SAMPLEDB;
use SAMPLEDB;

create table COMPANIES (
   ID bigint not null,
   NAME varchar(15),
   primary key (ID)
);
create table HOURLY_EMPLOYEES (
   ID bigint not null,
   NAME varchar(15),
   RATE double precision,
   COMPANY_ID bigint,
   primary key (ID)
);
create table SALARIED_EMPLOYEES (
   ID bigint not null,
   NAME varchar(15),
   SALARY double precision,
   COMPANY_ID bigint,
   primary key (ID)
);
alter table HOURLY_EMPLOYEES add index IDX1_COMPANY(COMPANY_ID), add constraint FK1_COMPANY foreign key (COMPANY_ID) references COMPANIES (ID);
alter table SALARIED_EMPLOYEES add index IDX2_COMPANY(COMPANY_ID), add constraint FK2_COMPANY foreign key (COMPANY_ID) references COMPANIES (ID);

insert into COMPANIES(ID,NAME) values(1,'ABC Company');

insert into HOURLY_EMPLOYEES(ID,NAME,RATE,COMPANY_ID) values(1,'Tom',100,1);

insert into HOURLY_EMPLOYEES(ID,NAME,RATE,COMPANY_ID) values(2,'Mike',200,1);

insert into SALARIED_EMPLOYEES(ID,NAME,SALARY,COMPANY_ID)
values(1,'Jack',5000,1);

insert into SALARIED_EMPLOYEES(ID,NAME,SALARY,COMPANY_ID)
values(2,'Linda',6000,1);

总结:

 

BusinessServic的main()方法调用test()方法,test()方法依次调用以下方法。

* findAllEmployees():检索数据库中所有的Employee对象

* loadCompany():加载一个Company对象

* saveEmployee():保存一个Employee对象

 

(1) 运行findAllEmployee()方法,它的代码如下:

 

List results=new ArrayList();

tx=session.beginTransaction();

List hourlyEmployees=session.find("from HourlyEmployee");

results.addAll(hourlyEmployee);

 

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);

  //抽象类不能用new来创建

 

  List salariedEmployees=session.find("from SalariedEmployee s where s.company.id="+id);

  company.getEmployees().addAll(salariedEmployees);

 

  tx.commit();

  return company;

  

  由于这种映射方式不支持多态关联,因此由Session的load()方法加载的Company<nobr>对象</nobr>的employees<nobr>集合</nobr>中不包含任何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<nobr>语句</nobr>:

  

  insert into HOURLY_EMPLOYEES (ID,NAME,RATE,CUSTOMER_ID) values(3,'Mary',300,1);

 

  如果employee<nobr>变量</nobr>引用SalariedEmployee<nobr>实例</nobr>,就向SE表插入一条记录。

 

分享到:
评论

相关推荐

    用Hibernate映射继承关系

    第三种映射方式是**类表映射**(Class-Table Inheritance Mapping),其中继承关系树的每个类(包括抽象类)都有其对应的表。这需要使用外键来建立类之间的关系。 ##### 14.3.1 创建映射文件 `Employee`类的映射文件...

    Hibernate映射继承关系的三种方案.docx

    本文将详细探讨Hibernate中处理继承关系的三种映射策略:subclass、joined-subclass以及union-subclass。 首先,让我们理解继承关系在面向对象编程中的重要性。继承允许我们创建一个类(子类)作为另一个类(父类)...

    hibernate映射继承关系(每个类都对应一张表)

    Hibernate,作为Java中广泛使用的对象关系映射(ORM)框架,提供了多种方式来处理继承关系的映射,其中一种就是"每个类都对应一张表"的策略。本文将深入探讨这种映射方式,以及如何在Hibernate中实现它。 首先,...

    Hibernate继承映射代码

    在Java世界中,Hibernate是一个非常流行的ORM(对象关系映射)框架,它允许开发者用面向对象的方式处理数据库操作。在大型项目中,由于业务需求复杂,我们常常会使用到类的继承来组织代码结构,而Hibernate提供了对...

    Hibernate继承映射的第一种策略:每棵类继承树对应一张表

    总之,单一表继承策略是一种简单且直观的Hibernate继承映射方式,适合类继承层次结构不深且子类数量较少的情况。但在大型项目或复杂的类继承结构中,可能需要考虑其他策略,如`JOINED`或`TABLE_PER_CLASS`。理解并...

    hibernate 映射继承 demo

    Hibernate支持四种继承映射策略:单表继承(Single Table Inheritance)、联合继承( Joined Subclass)、表 per 类继承(Table per Class Inheritance)和子类表(Concrete Table Inheritance)。在实际应用中,最...

    Hibernate映射关系配置:XML方式和注解方式

    本主题将深入探讨Hibernate框架下,如何通过XML映射文件和注解进行对象关系映射的配置,包括实体类的设计、字段映射、关联关系的建立,并可能结合具体代码实例进行解析,帮助读者理解并掌握这两种映射方式的使用。...

    Hibernate继承关系映射.pdf

    本文档主要聚焦于Hibernate框架下继承关系的映射,通过三种不同的策略——隐式继承映射、单表映射和关联表映射,来实现类的继承结构在数据库中的映射。 ### 隐式继承映射 #### 定义与配置 隐式继承映射也称为“表...

    hibernate的继承映射关系

    本文将深入探讨Hibernate如何处理继承多态映射关系,主要通过三种不同的策略来实现这一目标。 #### 继承多态的概念与背景 在面向对象编程中,继承允许子类继承父类的属性和方法,从而实现代码复用和功能扩展。而...

    自动生成hibernate映射文件和实体类

    1. Hibernate 是一种开源的持久层框架,提供了一个高效的数据访问机制,能够将 Java 对象与数据库表进行映射。 2. MyEclipse 是一个集成开发环境(IDE),提供了丰富的开发工具和插件,包括数据库管理、代码编辑、...

    生成hibernate映射文件工具

    hibernate映射文件是Java开发中用于对象关系映射(ORM)的重要组成部分,它将数据库表与Java类之间的关系进行定义,使得开发者无需编写大量的SQL语句,就能实现对数据库的操作。`生成hibernate映射文件工具`是为了...

    Hibernate 映射文件自动生成

    Hibernate通过XML或注解方式将Java类与数据库表进行映射,使得开发者可以使用面向对象的方式来处理数据库。然而,手动编写这些映射文件可能会耗费大量时间,因此“Hibernate 映射文件自动生成”是一个非常实用的功能...

    hibernate的多种映射关系

    在 Hibernate 中,映射关系是将数据库表与 Java 类之间的关联方式,使得对象模型可以与关系模型无缝对接。本篇文章将详细探讨 Hibernate 中的多种映射关系。 1. **一对一映射 (One-to-One)** 一对一映射表示两个...

    Hibernate教程20_关系映射案例三

    【标题】"Hibernate教程20_关系映射案例三"主要涵盖了在Hibernate框架中如何进行对象关系映射(ORM)的实践,特别是针对复杂关系的处理。在这个教程中,我们可能会学习到以下关键知识点: 1. **关系映射**:...

    hibernate映射和查询

    在 Hibernate 中,对象关系映射(ORM)是将数据库表映射到 Java 类的过程。这个过程通过 `hibernate.cfg.xml` 配置文件和实体类(Entity Class)来实现。在 `hibernate.cfg.xml` 文件中,我们配置数据库连接参数,如...

    Hibernate对象关系映射

    Hibernate对象关系映射一对多 很基础等文档

Global site tag (gtag.js) - Google Analytics