key words:hibernate,復合主鍵,composite-id
基于業務需求,您會需要使用兩個字段來作復合主鍵,例如在User數據表中,您也許會使用"name"與"phone"兩個字段來定義復合主鍵。
假設您這么建立User表格:
CREATE?TABLE?user?(
????name?VARCHAR(100)?NOT?NULL,
????phone?VARCHAR(50)?NOT?NULL,
????age?INT,
????PRIMARY?KEY(name,?phone)
);
在表格中,"name"與"age"被定義為復合主鍵,在映像時,您可以讓User類別直接帶有"name"與"age"這兩個屬性,而Hibernate要求復合主鍵類別要實作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;
?
//?復合主鍵類的對應類別必須實作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()方法被用作兩筆不同數據的識別依據;接著您可以使用<composite-id>在映射文件中定義復合主鍵與對象的屬性對應:
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>
在儲存數據方面,復合主鍵的儲存沒什么區別,現在的問題在于如何依據復合主鍵來查詢數據,例如使用load()方法,您可以創建一個User實例,并設定復合主鍵對應的屬性,接著再透過load()查詢對應的數據,例如:
User?user?=?new?User();
user.setName("bush");
user.setPhone("0970123456");
???????
Session?session?=?sessionFactory.openSession();
//?以實例設定復合主鍵并加載對應的數據
user?=?(User)?session.load(User.class,?user);
???????
System.out.println(user.getAge()?+?"\t"?+
??????????????????????????????????user.getName()?+?"\t"?+
??????????????????????????????????user.getPhone());
session.close();
?
?
可以將主鍵的信息獨立為一個類別,例如:
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();
????}
}
現在User類別的主鍵信息被分離出來了,例如:
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>
在查詢數據時,必須指定主鍵信息,例如:
UserPK?pk?=?new?UserPK();
pk.setName("bush");
pk.setPhone("0970123456");
??????
Session?session?=?sessionFactory.openSession();
//?以主鍵類實例設定復合主鍵并加載對應的數據
User?user?=?(User)?session.load(User.class,?pk);
??????
System.out.println(user.getAge()?+?"\t"?+
??????????????????????????????????user.getUserPK().getName()?+?"\t"?+
??????????????????????????????????user.getUserPK().getPhone());
session.close();
?
=================================================
再參考robbin的一篇文章
一個簡單的復合主鍵的做關聯類的例子??