Hibernate聯合主鍵映射
1. 實現方式一:將複合主鍵對應的屬性與實體其他普通屬性放在一起
2. 實現方式二:將主鍵屬性提取到一個主鍵類中,實體類只需包含主鍵類的一個引用
聯合主鍵的映射規則
1) 類中的每個主鍵屬性都對應到資料表中的每個主鍵列。
Hibernate要求具有聯合主鍵的實體類實現Serializable介面,並且重寫hashCode與equals方法。
1. 使用複合主鍵的實體類必須實現Serializable介面。必須實現Serializable介面的原因很簡單,我們尋找資料的時候是根據主鍵尋找的。開啟Hibernate的協助文檔我們可以找到get與load方法的聲明形式如下:
Object load(Class theClass,Serializable id)
Object get(Class theClass,Serializable id)
當我們尋找複合主鍵類的對象時,需要傳遞主索引值給get()或load()方法的id參數,而id參數只能接收一個實現了Serializable介面的對象。而複合主鍵類的主鍵不是一個屬性可以表示的,所以只能先new出複合主鍵類的執行個體(例如:new People()),然後使用主鍵屬性的set方法將主索引值賦值給主鍵屬性,然後將整個對象傳遞給get()或load()方法的id參數,實現主索引值的傳遞,所以複合主鍵的實體類必須實現Serializable介面。
應用情境:
主鍵類為什麼要序列化。如果多個該類對象同時放入記憶體中,在一個叢集系統中,其中一台伺服器當機了,需要將記憶體中對象寫到其它伺服器。同時,如果該伺服器記憶體以滿,需要用虛擬記憶體,這就需要序列化後才能寫到硬碟上。
2. 使用複合主鍵的實體類必須重寫equals和hashCode方法。必須重寫equals和hashCode方法也很好理解。這兩個方法使用於判斷兩個對象(兩條記錄)是否相等的。為什麼要判斷兩個對象是否相等呢。因為資料庫中的任意兩條記錄中的主索引值是不能相同的,所以我們在程式中只要確保了兩個對象的主索引值不同就可以防止主鍵約束違例的錯誤出現(程式中要確保對象的唯一性需要重寫hashCode()和equal()方法)。也許這裡你會奇怪為什麼不使用複合主鍵的實體類不重寫這兩個方法也沒有主鍵違例的情況出現,這是因為使用單一主鍵方式,主索引值是Hibernate來維護的,它會確保主鍵不會重複,而複合主鍵方式,主索引值是編程人員自己維護的,所以必須重寫equals和hashCode方法用於判斷兩個對象的主鍵是否相同。
3. 重寫的equals和hashCode方法,只與主鍵屬性有關,普通屬性不要影響這兩個方法進行判斷。這個原因很簡單,主鍵才能決定一條記錄,其他屬性不能決定一條記錄。
2) 將主鍵所對應屬性提取出一個類(稱之為主鍵類),並且主鍵類需要實現Serializable介面,重寫equals方法與hashCode方法,原因與上面一樣。
方式一:將複合主鍵對應的屬性與實體其他普通屬性放在一起
例如實體類People中"id"和"name"屬性對應複合主鍵:
Java代碼
1. public class People implements Serializable {
2. private static final long serialVersionUID = -4888836126783955019L;
3. private String id;
4. private String name;
5. private int age;
6.
7. public People() {
8. }
9.
10. public String getId() {
11. return id;
12. }
13.
14. public void setId(String id) {
15. this.id = id;
16. }
17.
18. public String getName() {
19. return name;
20. }
21.
22. public void setName(String name) {
23. this.name = name;
24. }
25.
26. public int getAge() {
27. return age;
28. }
29.
30. public void setAge(int age) {
31. this.age = age;
32. }
33.
34. @Override
35. public int hashCode() {
36. final int prime = 31;
37. int result = 1;
38. result = prime * result + ((id == null) ? 0 : id.hashCode());
39. result = prime * result + ((name == null) ? 0 : name.hashCode());
40. return result;
41. }
42.
43. @Override
44. public boolean equals(Object obj) {
45. if (this == obj)
46. return true;
47. if (obj == null)
48. return false;
49. if (getClass() != obj.getClass())
50. return false;
51. People other = (People) obj;
52. if (id == null) {
53. if (other.id != null)
54. return false;
55. } else if (!id.equals(other.id))
56. return false;
57. if (name == null) {
58. if (other.name != null)
59. return false;
60. } else if (!name.equals(other.name))
61. return false;
62. return true;
63. }
64.}
=======People.hbm.xml:
Xml代碼
1. <?xml version="1.0" encoding="utf-8"?>
2. <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
3. <hibernate-mapping>
4. <class name="com.suxiaolei.hibernate.pojos.People" table="people">
5. <!-- 複合主鍵使用composite-id標籤 -->
6. <composite-id>
7. <!-- key-property標籤表示哪一些屬性對應複合主鍵 -->
8. <key-property name="id" column="id" type="string">
9. </key-property>
10.<key-property name="name" column="name" type="string">
11.</key-property>
12.</composite-id>
13.<property name="age" column="age" type="integer">
14.</property>
15.</class>
16.</hibernate-mapping>
方式二:將主鍵屬性提取到一個主鍵類中,實體類只需包含主鍵類的一個引用
主鍵類:
======PeoplePrimaryKey.java
Java代碼
1. import java.io.Serializable;
2.
3. /*必須實現Serializable介面*/
4. public class PeoplePrimaryKey implements Serializable {
5. private static final long serialVersionUID = -1190986010439330142L; /* 複合主索引值 */
6. private String id;
7. private String name;
8.
9. public PeoplePrimaryKey() {
10. } /* 複合主索引值的get和set方法 */
11.
12. public String getId() {
13. return id;
14. }
15.
16. public void setId(String id) {
17. this.id = id;
18. }
19.
20. public String getName() {
21. return name;
22. }
23.
24. public void setName(String name) {
25. this.name = name;
26. }
27.
28. @Override
29. public int hashCode() {
30. final int prime = 31;
31. int result = 1;
32. result = prime * result + ((id == null) ? 0 : id.hashCode());
33. result = prime * result + ((name == null) ? 0 : name.hashCode());
34. return result;
35. }
36.
37. @Override
38. public boolean equals(Object obj) {
39. if (this == obj)
40. return true;
41. if (obj == null)
42. return false;
43. if (getClass() != obj.getClass())
44. return false;
45. PeoplePrimaryKey other = (PeoplePrimaryKey) obj;
46. if (id == null) {
47. if (other.id != null)
48. return false;
49. } else if (!id.equals(other.id))
50. return false;
51. if (name == null) {
52. if (other.name != null)
53. return false;
54. } else if (!name.equals(other.name))
55. return false;
56. return true;
57. }
58.}
===People.java
Java代碼
1. public class People { /* 持有主鍵類的一個引用,使用該引用作為這個類的OID */
2. private PeoplePrimaryKey peoplePrimaryKey;
3. private int age;
4.
5. public People() {
6. }
7.
8. public PeoplePrimaryKey getPeoplePrimaryKey() {
9. return peoplePrimaryKey;
10. }
11.
12. public void setPeoplePrimaryKey(PeoplePrimaryKey peoplePrimaryKey) {
13. this.peoplePrimaryKey = peoplePrimaryKey;
14. }
15.
16. public int getAge() {
17. return age;
18. }
19.
20. public void setAge(int age) {
21. this.age = age;
22. }
23.}
===People.hbm.xml檔案稍有一點變動:
Java代碼
1. <?xml version="1.0" encoding="utf-8"?>
2. <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
3. <hibernate-mapping>
4. <class name="com.suxiaolei.hibernate.pojos.People" table="people">
5. <!-- 複合主鍵使用composite-id標籤 -->
6. <!--name - 指定了複合主鍵對應哪一個屬性class - 指定了複合主鍵屬性的類型-->
7. <composite-id name="peoplePrimaryKey" class="com.suxiaolei.hibernate.pojos.PeoplePrimaryKey">
8. <!-- key-property指定了複合主鍵由哪些屬性群組成 -->
9. <key-property name="id" column="id" type="string">
10.</key-property>
11.<key-property name="name" column="name" type="string">
12.</key-property>
13.</composite-id>
14.<property name="age" column="age" type="integer">
15.</property>
16.</class>
17.</hibernate-mapping>