Hibernate復(fù)合主鍵映射
目 錄:
1. 實(shí)現(xiàn)方式一:將復(fù)合主鍵對(duì)應(yīng)的屬性與實(shí)體其他普通屬性放在一起
2. 實(shí)現(xiàn)方式二:將主鍵屬性提取到一個(gè)主鍵類中,實(shí)體類只需包含主鍵類的一個(gè)引用
在日常開發(fā)中會(huì)遇到這樣一種情況,數(shù)據(jù)庫中的某張表需要多個(gè)字段列才能唯一確定一行記錄,這時(shí)表需要使用復(fù)合主鍵。面對(duì)這樣的情況Hibernate為我們提供了兩種方式來解決復(fù)合主鍵問題。
方式一:將復(fù)合主鍵對(duì)應(yīng)的屬性與實(shí)體其他普通屬性放在一起
例如實(shí)體類People中"id"和"name"屬性對(duì)應(yīng)復(fù)合主鍵:
- /*實(shí)體類,使用復(fù)合主鍵必須實(shí)現(xiàn)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">
- <!-- 復(fù)合主鍵使用composite-id標(biāo)簽 -->
- <composite-id>
- <!-- key-property標(biāo)簽表示哪一些屬性對(duì)應(yīng)復(fù)合主鍵 -->
- <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中使用復(fù)合主鍵時(shí)需要注意一些規(guī)則:
1. 使用復(fù)合主鍵的實(shí)體類必須實(shí)現(xiàn)Serializable接口。必須實(shí)現(xiàn)Serializable接口的原因很簡單,我們查找數(shù)據(jù)的時(shí)候是根據(jù)主鍵查找的。打開Hibernate的幫助文檔我們可以找到get與load方法的聲明形式如下:
Object load(Class theClass,Serializable id)
Object get(Class theClass,Serializable id)
當(dāng)我們查找復(fù)合主鍵類的對(duì)象時(shí),需要傳遞主鍵值給get()或load()方法的id參數(shù),而id參數(shù)只能接收一個(gè)實(shí)現(xiàn)了Serializable接口的對(duì)象。而復(fù)合主鍵類的主鍵不是一個(gè)屬性可以表示的,所以只能先new出復(fù)合主鍵類的實(shí)例(例如:new People()),然后使用主鍵屬性的set方法將主鍵值賦值給主鍵屬性,然后將整個(gè)對(duì)象傳遞給get()或load()方法的id參數(shù),實(shí)現(xiàn)主鍵值的傳遞,所以復(fù)合主鍵的實(shí)體類必須實(shí)現(xiàn)Serializable接口。
2. 使用復(fù)合主鍵的實(shí)體類必須重寫equals和hashCode方法。必須重寫equals和hashCode方法也很好理解。這兩個(gè)方法使用于判斷兩個(gè)對(duì)象 (兩條記錄)是否相等的。為什么要判斷兩個(gè)對(duì)象是否相等呢?因?yàn)閿?shù)據(jù)庫中的任意兩條記錄中的主鍵值是不能相同的,所以我們?cè)诔绦蛑兄灰_保了兩個(gè)對(duì)象的主鍵值不同就可以防止主鍵約束違例的錯(cuò)誤出現(xiàn)。也許這里你會(huì)奇怪為什么不使用復(fù)合主鍵的實(shí)體類不重寫這兩個(gè)方法也沒有主鍵違例的情況出現(xiàn),這是因?yàn)槭褂脝我恢麈I方式,主鍵值是Hibernate來維護(hù)的,它會(huì)確保主鍵不會(huì)重復(fù),而復(fù)合主鍵方式,主鍵值是編程人員自己維護(hù)的,所以必須重寫equals和hashCode方法用于判斷兩個(gè)對(duì)象的主鍵是否相同。
3. 重寫的equals和hashCode方法,只與主鍵屬性有關(guān),普通屬性不要影響這兩個(gè)方法進(jìn)行判斷。這個(gè)原因很簡單,主鍵才能決定一條記錄,其他屬性不能決定一條記錄。
保存測(cè)試:
- 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();
- /*主鍵值由我們自己維護(hù)*/
- 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();
- }
- }
- }
看看數(shù)據(jù)庫:
數(shù)據(jù)被正確的插入到數(shù)據(jù)庫中了。
讀取數(shù)據(jù)測(cè)試:
- public class Client
- {
- public static void main(String[] args)
- {
- Session session = HibernateUtil.getSessionFactory().openSession();
- Transaction tx = null;
- try
- {
- tx = session.beginTransaction();
- /*查詢復(fù)合主鍵對(duì)象,需要先構(gòu)建主鍵*/
- People peoplePrimaryKey = new People();
- peoplePrimaryKey.setId("123456");
- peoplePrimaryKey.setName("zhangsan");
- /*然后將構(gòu)建的主鍵值傳入get方法中獲取對(duì)應(yīng)的People對(duì)象*/
- 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();
- }
- }
- }
控制臺(tái)輸出:
people age is:40
可以看到數(shù)據(jù)成功的取出了。
方式二:將主鍵屬性提取到一個(gè)主鍵類中,實(shí)體類只需包含主鍵類的一個(gè)引用。
主鍵類:
- /*必須實(shí)現(xiàn)Serializable接口*/
- public class PeoplePrimaryKey implements Serializable
- {
- private static final long serialVersionUID = -1190986010439330142L;
- /*復(fù)合主鍵值*/
- private String id;
- private String name;
- public PeoplePrimaryKey()
- {
- }
- /*復(fù)合主鍵值的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;
- }
- }
實(shí)體類:
- public class People
- {
- /*持有主鍵類的一個(gè)引用,使用該引用作為這個(gè)類的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文件稍有一點(diǎn)變動(dòng):
- <?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">
- <!-- 復(fù)合主鍵使用composite-id標(biāo)簽 -->
- <!--
- name - 指定了復(fù)合主鍵對(duì)應(yīng)哪一個(gè)屬性
- class - 指定了復(fù)合主鍵屬性的類型
- -->
- <composite-id name="peoplePrimaryKey" class="com.suxiaolei.hibernate.pojos.PeoplePrimaryKey">
- <!-- key-property指定了復(fù)合主鍵由哪些屬性組成 -->
- <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>
場(chǎng)景測(cè)試與方式一大同小異這里不再舉例了。主鍵類為什么實(shí)現(xiàn)Serializable接口和為什么重寫equals和hashCode方法上面已經(jīng)解釋的很清楚了。
原文鏈接:http://www.cnblogs.com/otomedaybreak/archive/2012/01/25/2329390.html
【編輯推薦】