[標題]:[原]Hibernate繼承映射-整個類層次映射為單個數據庫表
[時間]:2009-6-21
[摘要]:將整個類層次映射為單個數據庫表。這對于子類屬性不多的情況非常有效。每個子類由識別列(discriminator column)區(qū)分。優(yōu)點:實現簡單,并支持多態(tài)。同時數據訪問也比較簡單,因為數據庫表中包含了所有需要的信息。缺點:增加類層次中的耦合,類層次中任何類的屬性的增加都有會導致表的變更。另外,對子類屬性的修改錯誤將會影響到整個類的層次結構。當然也浪費了大量的數據庫空間。表中引入區(qū)分子類的字段,子類的字段不能創(chuàng)建為空。
[關鍵字]:Hibernate,ORM,關聯,繼承,持久化,映射,Abstract
[環(huán)境]:MyEclipse7,Hibernate3.2,MySQL5.1
[作者]:Winty (wintys@gmail.com) http://m.tkk7.com/wintys
[正文]:
將整個類層次映射為單個數據庫表。這對于子類屬性不多的情況非常有效。每個子類由識別列(discriminator column)區(qū)分。
優(yōu)點:
實現簡單,并支持多態(tài)。同時數據訪問也比較簡單,因為數據庫表中包含了所有需要的信息。
缺點:
增加類層次中的耦合,類層次中任何類的屬性的增加都有會導致表的變更。另外,對子類屬性的修改錯誤將會影響到整個類的層次結構。當然也浪費了大量的數據庫空間。表中引入區(qū)分子類的字段,子類的字段不能創(chuàng)建為空。
例:學校管理系統(tǒng)中的實體關系:

【圖: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),用于區(qū)分子類。
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://m.tkk7.com/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,-- 區(qū)分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&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);
//多態(tài)保存
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();
//不支持多態(tài)查詢
//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框架技術》-楊少波 : 清華大學出版社
原創(chuàng)作品,轉載請注明出處。
作者:Winty (wintys@gmail.com)
博客:http://m.tkk7.com/wintys
posted on 2009-06-21 13:17
天堂露珠 閱讀(397)
評論(0) 編輯 收藏 所屬分類:
Hibernate