摘自:http://www.blogjava.net/alex/archive/2006/11/09/80231.html
基于业务需求,您会需要使用两个字段来作复合主键,例如在User数据表中,您也许会使用"name"与"phone"两个字段来定义复合主键。
假设您这么建立User表格:
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->
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
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->
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
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->
<?
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()查询对应的数据,例如:
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->
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
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->
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
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->
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
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->
<?
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
>
在查询数据时,必须指定主键信息,例如:
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->
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();