這次我們來說一下hibernate的層次設計,層次設計也就是實體之間的繼承關系的設計。
也許這樣比較抽象,我們直接看例子。
1)我們先看一下普通的做法
直接上代碼:三個實類如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public class TItem implements Serializable{ //省略Get/Set方法 private int id; private String manufacture; private String name; } public class TBook extends TItem{ //省略Get/Set方法 private int pageCount; } public class TDVD extends TItem{ //省略Get/Set方法 private String regionCode; } |
這里我們需要三個映射文件,內容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
< class name = "TItem" table = "ITEM" > < id name = "id" column = "id" type = "java.lang.Integer" > < generator class = "native" /> </ id > < property name = "name" column = "name" type = "java.lang.String" /> < property name = "manufacture" column = "manufacture" type = "java.lang.String" /> </ class > < class name = "TBook" table = "Book" > < id name = "id" column = "id" type = "java.lang.Integer" > < generator class = "native" /> </ id > < property name = "name" column = "name" type = "java.lang.String" /> < property name = "manufacture" column = "manufacture" type = "java.lang.String" /> < property name = "pageCount" column = "pageCount" type = "java.lang.Integer" /> </ class > < class name = "TDVD" table = "DVD" > < id name = "id" column = "id" type = "java.lang.Integer" > < generator class = "native" /> </ id > < property name = "name" column = "name" type = "java.lang.String" /> < property name = "manufacture" column = "manufacture" type = "java.lang.String" /> < property name = "regionCode" column = "regionCode" type = "java.lang.String" /> </ class > |
很普通的映射文件,跟以前的沒什么區別。
下面我們直接寫一個測試方法:
1
2
3
4
5
6
7
8
9
10
11
|
public void testSelect() { Query query = session.createQuery( "from TItem " ); List list = query.list(); Iterator iter = list.iterator(); while (iter.hasNext()) { System.out.println( "Name:" +(((TItem)iter.next()).getName())); } } |
注意,這里我們是用TItem類,而不是具體的字類,這里它會自動去查找繼承于TItem類的子類,查出所有結果。這里涉及到一個多態模式,class標簽有屬性 polymorphism,它的默認值為implicit,這意味著不需要指定名稱就可以查詢出結果。如果為explicit則表明需要指定具體的類名時,才可以查出此類的結果。
2)上個例子中我們用到了三個映射文件,當我們需要修改時,就需要修改三個映射文件,這對于大的項目是很不可行的。而且每個表都有對應的主類的對應字段,這是多余的。所以我們有下面這種方法。
實體類還是跟1)中的一樣。我們把映射文件由三個改為一個,只保留TItem映射文件。但我們需要做相應的修改,現在內容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
< class name = "TItem" table = "ITEM" polymorphism = "explicit" > < id name = "id" column = "id" type = "java.lang.Integer" > < generator class = "native" /> </ id > < property name = "name" column = "name" type = "java.lang.String" /> < property name = "manufacture" column = "manufacture" type = "java.lang.String" /> < joined-subclass name = "TBook" table = "TBOOK" > < key column = "id" /> < property name = "pageCount" column = "pageCount" type = "java.lang.Integer" /> </ joined-subclass > < joined-subclass name = "TDVD" table = "TDVD" > < key column = "id" /> < property name = "regionCode" column = "regionCode" type = "java.lang.String" /> </ joined-subclass > </ class > |
這里,我們只有一個映射文件,但有一個joined-subclass標簽,它表明這個類繼承于當前類,<key>表明分表的主鍵,這里分表是指TBOOK和TDVD這兩個由子類對應的表。分表中只有字段在property中指定。
這樣當我們運行后生成的表就如下圖:
兩個子類對應的表只有我們通過property指定的字段。這樣就避免了表內有多個字段,使字表只維護其單獨字段,當item類進行改變時,也不用過多的進行修改。
3)再來了解另外一種方法實現層次設計,這就是通過在表內置入標志來實現。在hibernate的映射文件中我們通過descriminator標簽來進行實現。
廢話不多說,我們直接看例子:
我們把昨天的TItem的映射文件修改為:
1
2
3
4
5
6
7
8
9
|
< class name = "TItem" table = "ITEM" polymorphism = "explicit" > < id name = "id" column = "id" type = "java.lang.Integer" > < generator class = "native" /> </ id > < discriminator column = "category" type = "java.lang.String" /> < property name = "name" column = "name" type = "java.lang.String" /> < property name = "manufacture" column = "manufacture" type = "java.lang.String" /> </ class > |
看到中間,我們加入了一個discriminator標簽,它表明我們以下的兩個subclass通過哪個字段來進行區別。
1
2
3
4
5
6
|
< subclass name = "TBook" discriminator-value = "1" > < property name = "pageCount" column = "pageCount" /> </ subclass > < subclass name = "TDVD" discriminator-value = "2" > < property name = "regionCode" column = "regionCode" /> </ subclass > |
我們看到這兩段,它指明了當discriminator所指定的field的值為1時,表明它是TBook類,并且pageCount有值;當discriminator所指定的field值為2時,表明它是TDVD類,并且regionCode有值。
這樣我們就只需要用到一個表,就表明了它們幾個類的關系了,注意,這種方式對有過多子類的情況下,并不好,它會使主表的字段過多,會造成一定的設計上的不便。