前面的《Eclipse快速上手Hibernate--1. 入門實例 》等三篇文章已經談了Hibernate的入門以及利用工具創建的方法。這篇文章主要說說在Hibernate中的繼承映射。相關配置請參考前三篇文章。 如果程序中的對象含有繼承的關系,在Hibernate中有以下三種策略將這種關系映射到數據表上:· 每個類層次結構一個表(table per class hIErarchy)· 每個子類一個表(table per subclass) · 每個具體類一個表(table per concrete class)(有一些限制) 每個類層次結構一個表的方式是將所有繼承同一父類別的對象儲存在同一個表格中,為了做到這一點,需要在表格中使用識別字段來表示某一列(row)是屬於某個子類別或父類別,在這個主題中我們將先說明這個方法。 1. 創建項目 · 新建一個Java項目:InheritanceMapping,注意選中“創建單獨的源文件夾和輸出文件夾”,同時添加“用戶庫”:hibernate。 2. 編寫類文件 · 新建一個類,包名:javamxj.inheritance.one,類名:Animal。然後在生成的代碼中添加變量,再利用“生成 Getter 和 Setter”,具體方式同《Eclipse快速上手Hibernate--1. 入門實例 》文章中的編輯User.Java的方式一樣。
Animal.Java
/* * Hibernate - 繼承映射(每個類層次一個表) * 創建日期 2005-4-9 * @author javamxj(分享java快樂) * @link Blog: htpp://Javamxj.mblogger.cn * htpp://blog.csdn.Net/javamxj/ */package Javamxj.inheritance.one;/** * @hibernate.class * table="Animal" * discriminator-value="Animal" * @hibernate.discriminator * column="ANIMAL_TYPE" * type="string" * length = "10" */public abstract class Animal {private Long id;private String name;/** * @hibernate.id * column="ID" * generator-class="hilo" * unsaved-value="null" */public Long getId() {return id;}public void setId(Long id) {this.id = id;}/** * @hibernate.property * length = "24" */public String getName() {return name;}public void setName(String name) {this.name = name;}public abstract void makeSound();}
· 這個類是父類,值得注意是在類層次標記中添加了一個discriminator標記,並用它定義了一個字段“ANIMAL_TYPE”,這個字段就是用來識別某一列(row)是屬於某個子類別或父類別的。 · 子類Cat.javaCat.Java
package Javamxj.inheritance.one;/** * @hibernate.subclass * discriminator-value="Cat" */public class Cat extends Animal {private String FurColor;public void makeSound() {System.out.println("喵喵");}/** * @hibernate.property * length = "24" */public String getFurColor() {return FurColor;}public void setFurColor(String furColor) {FurColor = furColor;}}
· 子類Dog.javaDog.Java
package Javamxj.inheritance.one;/** * @hibernate.subclass * discriminator-value="Dog" */public class Dog extends Animal {private String category;public void makeSound() {System.out.println("汪汪");}/** * @hibernate.property * length = "24" */public String getCategory() {return category;}public void setCategory(String category) {this.category = category;}}
· 這兩個子類都很簡單,注意添加的hibernate.subclass的標記,指定其識別字段。 3. 構建文件Build.xml · 在項目根目錄下建立一個build.XML,要注意的是環境變量和數據庫的設置要符合自己的實際配置,這裡庫文件目錄的設置是"D:/Java/Hibernate/lib",參考文章《Eclipse快速上手Hibernate--1. 入門實例》中的設置。· 在MySQL中需要先建立一個HibernateTest數據庫,為了解決中文問題,使用了GBK編碼,注意“&”,這是由於XDoclet生成Hibernate配置文件時,會丟失一個“amp;”字符串(一個小Bug)。· 這裡我用build.xml中的“hibernatedoclet”任務直接生成“hibernate.cfg.XML”配置文件。
build.XML
· 好了,只要這四個文件就夠了,其它的會自動生成的。整個項目的結構如下: 4. 運行任務 · 雙擊“generate-hbm”任務,會發現在包中多了一個Animal.hbm.xml文件,在src目錄下會多了一個hibernate.cfg.XML文件,如果沒有,按F5鍵刷新一下(這裡建議打開Eclipse的“首選項”對話框,在“工作台”中勾選“自動刷新工作空間”和“在構建之前自動保存”這兩項,這樣以後不用每次都刷新了)。
Animal.hbm.XML
hibernate.cfg.XML
· 雙擊“schemaexport”任務,在項目根目錄下,會產生一個“schema-export.sql”文件。schema-export.sqldrop table if exists Animaldrop table if exists hibernate_unique_keycreate table Animal ( ID bigint not null, ANIMAL_TYPE varchar(10) not null, name varchar(24), furColor varchar(24), category varchar(24), primary key (ID))create table hibernate_unique_key ( next_hi integer )insert into hibernate_unique_key values ( 0 ) · 切換到數據庫中,會發現已經自動產生了數據表animal(表hibernate_unique_key是由於采用hilo主鍵策略生成的)。 5. 測試程序 · 好了,在包javamxj.inheritance.one下新建一個Demo.Java類,很簡單,前半部分是添加數據,後半部分是簡單的測試。
Demo.Java
package javamxj.inheritance.one;import java.util.Iterator;import Java.util.List;import net.sf.hibernate.HibernateException;import net.sf.hibernate.Session;import net.sf.hibernate.SessionFactory;import net.sf.hibernate.Transaction;import net.sf.hibernate.cfg.Configuration;public class Demo {public static void main(String[] args) {try {new Demo();} catch (HibernateException he) {he.printStackTrace();}}public Demo() throws HibernateException {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session sess = sf.openSession();Transaction tx = null;try {tx = sess.beginTransaction();Cat cat = new Cat();cat.setName("小白");cat.setFurColor("白色");sess.save(cat);Dog dog = new Dog();dog.setName("小黑");dog.setCategory("京巴狗");sess.save(dog);tx.commit();} catch (HibernateException e) {if (tx != null)tx.rollback();throw e;} finally {sess.close();}sess = sf.openSession();tx = null;try {tx = sess.beginTransaction();List animals = sess.find("from " + Animal.class.getName());for (Iterator it = animals.iterator(); it.hasNext();) {Animal animal = (Animal) it.next();System.out.println("動物 '" + animal.getName()+ "' 所在類是: " + animal.getClass().getName());System.out.print("發出叫聲: ");animal.makeSound();}tx.commit();} catch (HibernateException e) {if (tx != null)tx.rollback();throw e;} finally {sess.close();}}}
· 運行這個類,控制台輸出如下: · 同時,數據表中生成如下數據:注意其中為“NULL”的部分。 · 最後的項目結構如下: 小結: ● 優點:· 實現簡單。· 支持多態——對象角色發生變化,或存在多重角色時。· 報表操作實現簡單:表中包含了所有信息。● 缺點:· 增加類層次中的耦合。類層次中任何類的屬性的增加都會導致表的變更;某個子類屬性的修改會影響到整個層次結構,而不僅僅是該子類。· 浪費了一些數據庫空間。浪費空間的多少取決於繼承層次的深度。層次越深,不同的屬性越多,屬性的全集就越大,也就越浪費空間。· 可能需要指明具體的角色。 參考:· HIBERNATE - 符合Java習慣的關系數據庫持久化(第8章)· Hibernate 簡化繼承映射· Mapping Objects to Relational Databases: O/R Mapping In Detail· Mapping objects to relational databases 下篇文章會談談每個子類一個表的策略。