[原]Hibernate继承映射-整个类层次映射为单个数据库表

[标题]:[原]Hibernate继承映射-整个类层次映射为单个数据库表
[时间]:2009-6-21
[摘要]:将整个类层次映射为单个数据库表。这对于子类属性不多的情况非常有效。每个子类由识别列(discriminator column)区分。优点:实现简单,并支持多态。同时数据访问也比较简单,因为数据库表中包含了所有需要的信息。缺点:增加类层次中的耦合,类层次中任何类的属性的增加都有会导致表的变更。另外,对子类属性的修改错误将会影响到整个类的层次结构。当然也浪费了大量的数据库空间。表中引入区分子类的字段,子类的字段不能创建为空。
[关键字]:Hibernate,ORM,关联,继承,持久化,映射,Abstract
[环境]:MyEclipse7,Hibernate3.2,MySQL5.1
[作者]:Winty (wintys@gmail.com) http://www.blogjava.net/wintys

[正文]:
    将整个类层次映射为单个数据库表。这对于子类属性不多的情况非常有效。每个子类由识别列(discriminator column)区分。

优点:
    实现简单,并支持多态。同时数据访问也比较简单,因为数据库表中包含了所有需要的信息。

缺点:
    增加类层次中的耦合,类层次中任何类的属性的增加都有会导致表的变更。另外,对子类属性的修改错误将会影响到整个类的层次结构。当然也浪费了大量的数据库空间。表中引入区分子类的字段,子类的字段不能创建为空。

    
    例:学校管理系统中的实体关系:



 
    【图:department.jpg】

1、概述
a.实体类
public class Department {
    ......
    private Set<Person> persons;
    ......
}

public abstract class Person {
    ......
    private Department department;
    ......
}

public class Student extends Person {
    ......
}

public class Teacher extends Person {
    ......
}

b.数据库表
    将整个类层次的所有属性全部放入一张表中,不过新增一个字段(discriminator column),用于区分子类。

c.配置文件

Person.hbm.xml:
......
<discriminator column="personType" type="string" />
......


2、实体类:
Department.java:

package wintys.hibernate.inheritance.allinone;

import java.util.Set;
//Person类相同,直接引用
import wintys.hibernate.inheritance.allinone.Person;

/**
 *
 * @version 2009-06-20
 * @author Winty (wintys@gmail.com)
 *
 */
public class Department {
    private Integer id;
    private String name;
    private String desc;
    //Department 与 Person一对多
    private Set<Person> persons;
    
    
    public Department(){
        
    }
    
    public Department(String name , String desc){
        this.name = name;
        this.desc = desc;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }

    public Set<Person> getPersons() {
        return persons;
    }

    public void setPersons(Set<Person> persons) {
        this.persons = persons;
    }
}



Person.java、Student.java、Teacher.java与wintys.hibernate.inheritance.concrete包中相同,直接复制过来即可。因为Person.java引用的Department与concrete包中的Department不一样,所以要把Person.java等复制过来,而不是直接import。


3、数据库表:



 
【图:allinone_db.jpg】

db.sql:

-- Author:Winty (wintys@gmail.com)
-- Date:2009-06-20
-- http://www.blogjava.net/wintys

USE db;

-- Department
CREATE TABLE mydepartment(
    id      INT(4) NOT NULL,
    name    VARCHAR(100),
    descs  VARCHAR(100),
    PRIMARY KEY(id)
);

-- Person 、Student、Teacher在一张表中定义
CREATE TABLE myperson(
    id              INT(4) NOT NULL,
    name            VARCHAR(100),
    dept            INT(4), -- 与Department关联
    personType        VARCHAR(20) NOT NULL,-- 区分Student和Teacher
    studentMajor    VARCHAR(100),
    teacherSalary   FLOAT(7,2),
    PRIMARY KEY(id),
    CONSTRAINT FK_dept_p FOREIGN KEY(dept) REFERENCES mydepartment(id)
);



4、映射文件:



 
【图:allinone_mapping.jpg】


Department.hbm.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
    Mapping file autogenerated by MyEclipse Persistence Tools
-->

<hibernate-mapping>
    <class name="wintys.hibernate.inheritance.allinone.Department" table="mydepartment" catalog="db">
        <id name="id" type="int">
            <column name="id" not-null="true"/>
            <generator class="increment" />
        </id>
        <property name="name" />
        <property name="desc" type="string" column="descs"/>
        <!-- 实现一对多映射 -->
        <set name="persons" inverse="true">
            <key column="dept" />
            <one-to-many class="wintys.hibernate.inheritance.allinone.Person"/>
        </set>
    </class>
</hibernate-mapping>



Person.hbm.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
    Mapping file autogenerated by MyEclipse Persistence Tools
-->

<hibernate-mapping>
    <class name="wintys.hibernate.inheritance.allinone.Person" table="myperson" catalog="db">
        <id name="id" type="int">
            <column name="id" not-null="true"/>
            <generator class="increment" />
        </id>
        <discriminator column="personType" type="string" />
        <property name="name" />     
        <many-to-one name="department"
                    unique="true"
                    column="dept"
                    class="wintys.hibernate.inheritance.allinone.Department"/>
        <subclass name="wintys.hibernate.inheritance.allinone.Student" discriminator-value="Student">
            <property name="studentMajor" />
        </subclass>
        <subclass name="wintys.hibernate.inheritance.allinone.Teacher" discriminator-value="Teacher">
            <property name="teacherSalary" column="teacherSalary" type="float"/>
        </subclass>        
    </class>
</hibernate-mapping>



hibernate.cfg.xml:

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<!-- Generated by MyEclipse Hibernate Tools.                   -->
<hibernate-configuration>

<session-factory>
    <property name="connection.username">root</property>
    <property name="connection.url">
        jdbc:mysql://localhost:3306/db?useUnicode=true&amp;characterEncoding=utf-8
    </property>
    <property name="dialect">
        org.hibernate.dialect.MySQLDialect
    </property>
    <property name="myeclipse.connection.profile">MySQLDriver</property>
    <property name="connection.password">root</property>
    <property name="connection.driver_class">
        com.mysql.jdbc.Driver
    </property>
    <property name="show_sql">true</property>
    <mapping
        resource="wintys/hibernate/inheritance/allinone/Department.hbm.xml" />
    <mapping
        resource="wintys/hibernate/inheritance/allinone/Person.hbm.xml" />

</session-factory>

</hibernate-configuration>


4、使用测试:
DAOBean.java:

package wintys.hibernate.inheritance.allinone;

import wintys.hibernate.inheritance.concrete.DAO;
import wintys.hibernate.inheritance.concrete.HibernateUtil;

import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;

/**
 *
 * @version 2009-06-20
 * @author Winty (wintys@gmail.com)
 *
 */
public class DAOBean implements DAO {

    @Override
    public void insert() {
        Transaction tc = null;
        try{
            Department dept = new Department("college of math" , "the top 3 college");
            Person p1,p2;
            p1 = new Student("Sam" , "Math");
            p1.setDepartment(dept);
            p2 = new Teacher("Martin" , new Float(15000f));
            p2.setDepartment(dept);
            
            Session session = HibernateUtil.getSession();
            tc = session.beginTransaction();
                        
            session.save(dept);
            //多态保存
            session.save(p1);
            session.save(p2);
        
            tc.commit();
        }catch(HibernateException e){
            try{
                if(tc != null)
                    tc.rollback();
            }catch(Exception ex){
                System.err.println(ex.getMessage());
            }
            System.err.println(e.getMessage());
        }finally{
            HibernateUtil.closeSession();            
        }    
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> List<T> select(String hql) {
        List<T> items = null;
        Transaction tc = null;
        try{
            Session session = HibernateUtil.getSession();
            tc = session.beginTransaction();
                        
            Query query = session.createQuery(hql);
            items = query.list();
            
            tc.commit();
        }catch(HibernateException e){
            try{
                if(tc != null){
                    tc.rollback();
                    items = null;
                }
            }catch(Exception ex){
                System.err.println(ex.getMessage());
            }
            System.err.println(e.getMessage());
        }finally{
            //HibernateUtil.closeSession();            
        }
        
        return items;
    }

}



Test.java:

package wintys.hibernate.inheritance.allinone;

import java.util.Iterator;
import java.util.List;

import wintys.hibernate.inheritance.concrete.DAO;
import wintys.hibernate.inheritance.concrete.HibernateUtil;

public class Test {

    public static void main(String[] args) {
        String config = "wintys/hibernate/inheritance/allinone/hibernate.cfg.xml";
        HibernateUtil.setConfigFile(config);
        
        DAO dao = new DAOBean();
        //dao.insert();
        //不支持多态查询
        //Error:Person is not mapped
        //List<Person> ps = dao.select("from Person");
        //System.out.println(printStudentOrTeacher(ps));
        
        /*List<Student> students = dao.select("from Student");
        System.out.println(printStudentOrTeacher(students));*/
        
        List<Student> teachers = dao.select("from Teacher");
        System.out.println(printStudentOrTeacher(teachers));        
    }
    
    public static String printStudentOrTeacher(List<? extends Person> students){
        String str = "";
        Iterator<? extends Person> it = students.iterator();
        while(it.hasNext()){
            Person person = it.next();
            int id = person.getId();
            String name = person.getName();
            Department dept = person.getDepartment();
                
            int deptId = dept.getId();
            String deptName = dept.getName();
            String deptDesc = dept.getDesc();
            
            str += "id:" +id + ""n";
            str += "name:" + name + ""n";
            if(person instanceof Student)
                str += "major:"  + ((Student) person).getStudentMajor() + ""n";
            if(person instanceof Teacher)
                str += "salary:" + ((Teacher) person).getTeacherSalary().toString() + ""n";
            str += "dept:" + ""n";
            str += "  deptId:" + deptId + ""n";
            str += "  deptName:" + deptName + ""n";
            str += "  deptDesc:" + deptDesc + ""n";    
            str += ""n";
        }
        return str;
    }
}



5、运行结果



 
【图:allinone_tables.jpg】

控制台显示:

......
Hibernate: select max(id) from mydepartment
Hibernate: select max(id) from myperson
Hibernate: insert into db.mydepartment (name, descs, id) values (?, ?, ?)
Hibernate: insert into db.myperson (name, dept, studentMajor, personType, id) values (?, ?, ?, 'Student', ?)
Hibernate: insert into db.myperson (name, dept, teacherSalary, personType, id) values (?, ?, ?, 'Teacher', ?)
Hibernate: select person0_.id as id1_, person0_.name as name1_, person0_.dept as dept1_, person0_.studentMajor as studentM5_1_, person0_.teacherSalary as teacherS6_1_, person0_.personType as personType1_ from db.myperson person0_
Hibernate: select department0_.id as id0_0_, department0_.name as name0_0_, department0_.descs as descs0_0_ from db.mydepartment department0_ where department0_.id=?
id:1
name:Sam
major:Math
dept:
  deptId:1
  deptName:college of math
  deptDesc:the top 3 college

id:2
name:Martin
salary:15000.0
dept:
  deptId:1
  deptName:college of math
  deptDesc:the top 3 college


[参考资料]:
《J2EE项目实训--Hibernate框架技术》-杨少波 : 清华大学出版社

原创作品,转载请注明出处。
作者:Winty (wintys@gmail.com)
博客:http://www.blogjava.net/wintys

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值