key words:hibernate,復(fù)合主鍵,composite-id
基于業(yè)務(wù)需求,您會(huì)需要使用兩個(gè)字段來(lái)作復(fù)合主鍵,例如在User數(shù)據(jù)表中,您也許會(huì)使用"name"與"phone"兩個(gè)字段來(lái)定義復(fù)合主鍵。
假設(shè)您這么建立User表格:
CREATE?TABLE?user?(
????name?VARCHAR(100)?NOT?NULL,
????phone?VARCHAR(50)?NOT?NULL,
????age?INT,
????PRIMARY?KEY(name,?phone)
);
在表格中,"name"與"age"被定義為復(fù)合主鍵,在映像時(shí),您可以讓User類別直接帶有"name"與"age"這兩個(gè)屬性,而Hibernate要求復(fù)合主鍵類別要實(shí)作Serializable接口,并定義equals()與hashCode()方法:
User.java
package?onlyfun.caterpillar;
?
import?java.io.Serializable;
import?org.apache.commons.lang.builder.EqualsBuilder;
import?org.apache.commons.lang.builder.HashCodeBuilder;
?
//?復(fù)合主鍵類的對(duì)應(yīng)類別必須實(shí)作Serializable接口
public?class?User?implements?Serializable?{
????private?String?name;
????private?String?phone;
????private?Integer?age;
???
????public?User()?{
????}
?
????public?Integer?getAge()?{
????????return?age;
????}
?
????public?void?setAge(Integer?age)?{
????????this.age?=?age;
????}
?
????public?String?getName()?{
????????return?name;
????}
?
????public?void?setName(String?name)?{
????????this.name?=?name;
????}
?
????public?String?getPhone()?{
????????return?phone;
????}
?
????public?void?setPhone(String?phone)?{
????????this.phone?=?phone;
????}
???
????//?必須重新定義equals()與hashCode()
????public?boolean?equals(Object?obj)?{
????????if(obj?==?this)?{
????????????return?true;
????????}
???????
????????if(!(obj?instanceof?User))?{
????????????return?false;
????????}
???????
????????User?user?=?(User)?obj;
????????return?new?EqualsBuilder()
?????????????????.append(this.name,?user.getName())
?????????????????.append(this.phone,?user.getPhone())
?????????????????.isEquals();
???????
????}
???
????public?int?hashCode()?{
????????return?new?HashCodeBuilder()
?????????????????.append(this.name)
?????????????????.append(this.phone)
?????????????????.toHashCode();
????}
}
equals()與hashCode()方法被用作兩筆不同數(shù)據(jù)的識(shí)別依據(jù);接著您可以使用<composite-id>在映射文件中定義復(fù)合主鍵與對(duì)象的屬性對(duì)應(yīng):
User.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="onlyfun.caterpillar.User"?table="user">
????????<composite-id>
????????????<key-property?name="name"
??????????????????????????column="name"
??????????????????????????type="java.lang.String"/>
????????????<key-property?name="phone"
??????????????????????????column="phone"
??????????????????????????type="java.lang.String"/>
????????</composite-id>
?
????????<property?name="age"?column="age"?type="java.lang.Integer"/>
???
????</class>
</hibernate-mapping>
在儲(chǔ)存數(shù)據(jù)方面,復(fù)合主鍵的儲(chǔ)存沒什么區(qū)別,現(xiàn)在的問題在于如何依據(jù)復(fù)合主鍵來(lái)查詢數(shù)據(jù),例如使用load()方法,您可以創(chuàng)建一個(gè)User實(shí)例,并設(shè)定復(fù)合主鍵對(duì)應(yīng)的屬性,接著再透過load()查詢對(duì)應(yīng)的數(shù)據(jù),例如:
User?user?=?new?User();
user.setName("bush");
user.setPhone("0970123456");
???????
Session?session?=?sessionFactory.openSession();
//?以實(shí)例設(shè)定復(fù)合主鍵并加載對(duì)應(yīng)的數(shù)據(jù)
user?=?(User)?session.load(User.class,?user);
???????
System.out.println(user.getAge()?+?"\t"?+
??????????????????????????????????user.getName()?+?"\t"?+
??????????????????????????????????user.getPhone());
session.close();
?
?
可以將主鍵的信息獨(dú)立為一個(gè)類別,例如:
UserPK.java
package?onlyfun.caterpillar;
?
import?java.io.Serializable;
?
import?org.apache.commons.lang.builder.EqualsBuilder;
import?org.apache.commons.lang.builder.HashCodeBuilder;
?
public?class?UserPK?implements?Serializable?{
????private?String?name;
????private?String?phone;
?
????public?String?getName()?{
????????return?name;
????}
?
????public?void?setName(String?name)?{
????????this.name?=?name;
????}
?
????public?String?getPhone()?{
????????return?phone;
????}
?
????public?void?setPhone(String?phone)?{
????????this.phone?=?phone;
????}
???
????public?boolean?equals(Object?obj)?{
????????if(obj?==?this)?{
????????????return?true;
????????}
???????
????????if(!(obj?instanceof?User))?{
????????????return?false;
????????}
???????
????????UserPK?pk?=?(UserPK)?obj;
????????return?new?EqualsBuilder()
?????????????????.append(this.name,?pk.getName())
?????????????????.append(this.phone,?pk.getPhone())
?????????????????.isEquals();
???????
????}
???
????public?int?hashCode()?{
????????return?new?HashCodeBuilder()
?????????????????.append(this.name)
?????????????????.append(this.phone)
?????????????????.toHashCode();
????}
}
現(xiàn)在User類別的主鍵信息被分離出來(lái)了,例如:
User.java
package?onlyfun.caterpillar;
?
import?java.io.Serializable;
?
public?class?User?implements?Serializable?{
????private?UserPK?userPK;?//?主鍵
????private?Integer?age;
???
????public?User()?{
????}
?
????public?UserPK?getUserPK()?{
????????return?userPK;
????}
?
????public?void?setUserPK(UserPK?userPK)?{
????????this.userPK?=?userPK;
????}
?
????public?Integer?getAge()?{
????????return?age;
????}
?
????public?void?setAge(Integer?age)?{
????????this.age?=?age;
????}
}
在映像文件方面,需要指定主鍵類的信息,例如:
User.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="onlyfun.caterpillar.User"?table="user">
????????<composite-id?name="userPK"
??????????????????????class="onlyfun.caterpillar.UserPK"
??????????????????????unsaved-value="any">
????????????<key-property?name="name"
??????????????????????????column="name"
??????????????????????????type="java.lang.String"/>
????????????<key-property?name="phone"
??????????????????????????column="phone"
??????????????????????????type="java.lang.String"/>
????????</composite-id>
???????
????????<property?name="age"?column="age"?type="java.lang.Integer"/>
???
????</class>
?
</hibernate-mapping>
在查詢數(shù)據(jù)時(shí),必須指定主鍵信息,例如:
UserPK?pk?=?new?UserPK();
pk.setName("bush");
pk.setPhone("0970123456");
??????
Session?session?=?sessionFactory.openSession();
//?以主鍵類實(shí)例設(shè)定復(fù)合主鍵并加載對(duì)應(yīng)的數(shù)據(jù)
User?user?=?(User)?session.load(User.class,?pk);
??????
System.out.println(user.getAge()?+?"\t"?+
??????????????????????????????????user.getUserPK().getName()?+?"\t"?+
??????????????????????????????????user.getUserPK().getPhone());
session.close();
?
=================================================
再參考robbin的一篇文章
一個(gè)簡(jiǎn)單的復(fù)合主鍵的做關(guān)聯(lián)類的例子??