Hibernate復合主鍵映射
目 錄:
1. 實現方式一:將復合主鍵對應的屬性與實體其他普通屬性放在一起
2. 實現方式二:將主鍵屬性提取到一個主鍵類中,實體類只需包含主鍵類的一個引用
在日常開發中會遇到這樣一種情況,數據庫中的某張表需要多個字段列才能唯一確定一行記錄,這時表需要使用復合主鍵。面對這樣的情況Hibernate為我們提供了兩種方式來解決復合主鍵問題。
例如實體類People中"id"和"name"屬性對應復合主鍵:
- /*實體類,使用復合主鍵必須實現Serializable接口*/
- public class People implements Serializable
- {
- private static final long serialVersionUID = -4888836126783955019L;
- private String id;
- private String name;
- private int age;
- public People()
- {
- }
- public String getId()
- {
- return id;
- }
- public void setId(String id)
- {
- this.id = id;
- }
- public String getName()
- {
- return name;
- }
- public void setName(String name)
- {
- this.name = name;
- }
- public int getAge()
- {
- return age;
- }
- public void setAge(int age)
- {
- this.age = age;
- }
- @Override
- public int hashCode()
- {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((id == null) ? 0 : id.hashCode());
- result = prime * result + ((name == null) ? 0 : name.hashCode());
- return result;
- }
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- People other = (People) obj;
- if (id == null)
- {
- if (other.id != null)
- return false;
- }
- else if (!id.equals(other.id))
- return false;
- if (name == null)
- {
- if (other.name != null)
- return false;
- }
- else if (!name.equals(other.name))
- return false;
- return true;
- }
- }
People.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">
- <hibernate-mapping>
- <class name="com.suxiaolei.hibernate.pojos.People" table="people">
- <!-- 復合主鍵使用composite-id標簽 -->
- <composite-id>
- <!-- key-property標簽表示哪一些屬性對應復合主鍵 -->
- <key-property name="id" column="id" type="string"></key-property>
- <key-property name="name" column="name" type="string"></key-property>
- </composite-id>
- <property name="age" column="age" type="integer"></property>
- </class>
- </hibernate-mapping>
Hibernate中使用復合主鍵時需要注意一些規則:
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方法也很好理解。這兩個方法使用于判斷兩個對象 (兩條記錄)是否相等的。為什么要判斷兩個對象是否相等呢?因為數據庫中的任意兩條記錄中的主鍵值是不能相同的,所以我們在程序中只要確保了兩個對象的主鍵值不同就可以防止主鍵約束違例的錯誤出現。也許這里你會奇怪為什么不使用復合主鍵的實體類不重寫這兩個方法也沒有主鍵違例的情況出現,這是因為使用單一主鍵方式,主鍵值是Hibernate來維護的,它會確保主鍵不會重復,而復合主鍵方式,主鍵值是編程人員自己維護的,所以必須重寫equals和hashCode方法用于判斷兩個對象的主鍵是否相同。
3. 重寫的equals和hashCode方法,只與主鍵屬性有關,普通屬性不要影響這兩個方法進行判斷。這個原因很簡單,主鍵才能決定一條記錄,其他屬性不能決定一條記錄。
保存測試:
- public class Client
- {
- public static void main(String[] args)
- {
- Session session = HibernateUtil.getSessionFactory().openSession();
- Transaction tx = null;
- try
- {
- tx = session.beginTransaction();
- People people = new People();
- /*主鍵值由我們自己維護*/
- people.setId("123456");
- people.setName("zhangsan");
- people.setAge(40);
- session.save(people);
- tx.commit();
- }
- catch (Exception e)
- {
- if(tx != null)
- {
- tx.rollback();
- }
- e.printStackTrace();
- }
- finally
- {
- session.close();
- }
- }
- }
看看數據庫:
數據被正確的插入到數據庫中了。
讀取數據測試:
- public class Client
- {
- public static void main(String[] args)
- {
- Session session = HibernateUtil.getSessionFactory().openSession();
- Transaction tx = null;
- try
- {
- tx = session.beginTransaction();
- /*查詢復合主鍵對象,需要先構建主鍵*/
- People peoplePrimaryKey = new People();
- peoplePrimaryKey.setId("123456");
- peoplePrimaryKey.setName("zhangsan");
- /*然后將構建的主鍵值傳入get方法中獲取對應的People對象*/
- People people = (People)session.get(People.class, peoplePrimaryKey);
- System.out.println("people age is:"+people.getAge());
- tx.commit();
- }
- catch (Exception e)
- {
- if(tx != null)
- {
- tx.rollback();
- }
- e.printStackTrace();
- }
- finally
- {
- session.close();
- }
- }
- }
控制臺輸出:
people age is:40
可以看到數據成功的取出了。
方式二:將主鍵屬性提取到一個主鍵類中,實體類只需包含主鍵類的一個引用。
主鍵類:
- /*必須實現Serializable接口*/
- public class PeoplePrimaryKey implements Serializable
- {
- private static final long serialVersionUID = -1190986010439330142L;
- /*復合主鍵值*/
- private String id;
- private String name;
- public PeoplePrimaryKey()
- {
- }
- /*復合主鍵值的get和set方法*/
- public String getId()
- {
- return id;
- }
- public void setId(String id)
- {
- this.id = id;
- }
- public String getName()
- {
- return name;
- }
- public void setName(String name)
- {
- this.name = name;
- }
- @Override
- public int hashCode()
- {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((id == null) ? 0 : id.hashCode());
- result = prime * result + ((name == null) ? 0 : name.hashCode());
- return result;
- }
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- PeoplePrimaryKey other = (PeoplePrimaryKey) obj;
- if (id == null)
- {
- if (other.id != null)
- return false;
- }
- else if (!id.equals(other.id))
- return false;
- if (name == null)
- {
- if (other.name != null)
- return false;
- }
- else if (!name.equals(other.name))
- return false;
- return true;
- }
- }
實體類:
- public class People
- {
- /*持有主鍵類的一個引用,使用該引用作為這個類的OID*/
- private PeoplePrimaryKey peoplePrimaryKey;
- private int age;
- public People()
- {
- }
- public PeoplePrimaryKey getPeoplePrimaryKey()
- {
- return peoplePrimaryKey;
- }
- public void setPeoplePrimaryKey(PeoplePrimaryKey peoplePrimaryKey)
- {
- this.peoplePrimaryKey = peoplePrimaryKey;
- }
- public int getAge()
- {
- return age;
- }
- public void setAge(int age)
- {
- this.age = age;
- }
- }
People.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">
- <hibernate-mapping>
- <class name="com.suxiaolei.hibernate.pojos.People" table="people">
- <!-- 復合主鍵使用composite-id標簽 -->
- <!--
- name - 指定了復合主鍵對應哪一個屬性
- class - 指定了復合主鍵屬性的類型
- -->
- <composite-id name="peoplePrimaryKey" class="com.suxiaolei.hibernate.pojos.PeoplePrimaryKey">
- <!-- key-property指定了復合主鍵由哪些屬性組成 -->
- <key-property name="id" column="id" type="string"></key-property>
- <key-property name="name" column="name" type="string"></key-property>
- </composite-id>
- <property name="age" column="age" type="integer"></property>
- </class>
- </hibernate-mapping>
場景測試與方式一大同小異這里不再舉例了。主鍵類為什么實現Serializable接口和為什么重寫equals和hashCode方法上面已經解釋的很清楚了。
原文鏈接:http://www.cnblogs.com/otomedaybreak/archive/2012/01/25/2329390.html
【編輯推薦】