hibernate复合主键的操作
摘自:http://www.blogjava.net/alex/archive/2006/11/09/80231.html
基于业务需求,您会需要使用两个字段来作复合主键,例如在User数据表中,您也许会使用"name"与"phone"两个字段来定义复合主键。
假设您这么建立User表格:
nameVARCHAR(100)NOTNULL,
phoneVARCHAR(50)NOTNULL,
ageINT,
PRIMARYKEY(name,phone)
);
在表格中,"name"与"age"被定义为复合主键,在映像时,您可以让User类别直接带有"name"与"age"这两个属性,而Hibernate要求复合主键类别要实作Serializable接口,并定义equals()与hashCode()方法:
User.java
importjava.io.Serializable;
importorg.apache.commons.lang.builder.EqualsBuilder;
importorg.apache.commons.lang.builder.HashCodeBuilder;
//复合主键类的对应类别必须实作Serializable接口
publicclassUserimplementsSerializable{
privateStringname;
privateStringphone;
privateIntegerage;
publicUser(){
}
publicIntegergetAge(){
returnage;
}
publicvoidsetAge(Integerage){
this.age=age;
}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicStringgetPhone(){
returnphone;
}
publicvoidsetPhone(Stringphone){
this.phone=phone;
}
//必须重新定义equals()与hashCode()
publicbooleanequals(Objectobj){
if(obj==this){
returntrue;
}
if(!(objinstanceofUser)){
returnfalse;
}
Useruser=(User)obj;
returnnewEqualsBuilder()
.append(this.name,user.getName())
.append(this.phone,user.getPhone())
.isEquals();
}
publicinthashCode(){
returnnewHashCodeBuilder()
.append(this.name)
.append(this.phone)
.toHashCode();
}
}
equals()与hashCode()方法被用作两笔不同数据的识别依据;接着您可以使用<composite-id>在映射文件中定义复合主键与对象的属性对应:
User.hbm.xml
<!DOCTYPEhibernate-mapping
PUBLIC"-//Hibernate/HibernateMappingDTD3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="onlyfun.caterpillar.User"table="user">
<composite-id>
<key-propertyname="name"
column="name"
type="java.lang.String"/>
<key-propertyname="phone"
column="phone"
type="java.lang.String"/>
</composite-id>
<propertyname="age"column="age"type="java.lang.Integer"/>
</class>
</hibernate-mapping>
在储存数据方面,复合主键的储存没什么区别,现在的问题在于如何依据复合主键来查询数据,例如使用load()方法,您可以创建一个User实例,并设定复合主键对应的属性,接着再透过load()查询对应的数据,例如:
user.setName("bush");
user.setPhone("0970123456");
Sessionsession=sessionFactory.openSession();
//以实例设定复合主键并加载对应的数据
user=(User)session.load(User.class,user);
System.out.println(user.getAge()+"\t"+
user.getName()+"\t"+
user.getPhone());
session.close();
可以将主键的信息独立为一个类别,例如:
UserPK.java
importjava.io.Serializable;
importorg.apache.commons.lang.builder.EqualsBuilder;
importorg.apache.commons.lang.builder.HashCodeBuilder;
publicclassUserPKimplementsSerializable{
privateStringname;
privateStringphone;
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicStringgetPhone(){
returnphone;
}
publicvoidsetPhone(Stringphone){
this.phone=phone;
}
publicbooleanequals(Objectobj){
if(obj==this){
returntrue;
}
if(!(objinstanceofUser)){
returnfalse;
}
UserPKpk=(UserPK)obj;
returnnewEqualsBuilder()
.append(this.name,pk.getName())
.append(this.phone,pk.getPhone())
.isEquals();
}
publicinthashCode(){
returnnewHashCodeBuilder()
.append(this.name)
.append(this.phone)
.toHashCode();
}
}
现在User类别的主键信息被分离出来了,例如:
User.java
importjava.io.Serializable;
publicclassUserimplementsSerializable{
privateUserPKuserPK;//主键
privateIntegerage;
publicUser(){
}
publicUserPKgetUserPK(){
returnuserPK;
}
publicvoidsetUserPK(UserPKuserPK){
this.userPK=userPK;
}
publicIntegergetAge(){
returnage;
}
publicvoidsetAge(Integerage){
this.age=age;
}
}
在映像文件方面,需要指定主键类的信息,例如:
User.hbm.xml
<!DOCTYPEhibernate-mapping
PUBLIC"-//Hibernate/HibernateMappingDTD3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="onlyfun.caterpillar.User"table="user">
<composite-idname="userPK"
class="onlyfun.caterpillar.UserPK"
unsaved-value="any">
<key-propertyname="name"
column="name"
type="java.lang.String"/>
<key-propertyname="phone"
column="phone"
type="java.lang.String"/>
</composite-id>
<propertyname="age"column="age"type="java.lang.Integer"/>
</class>
</hibernate-mapping>
在查询数据时,必须指定主键信息,例如:
pk.setName("bush");
pk.setPhone("0970123456");
Sessionsession=sessionFactory.openSession();
//以主键类实例设定复合主键并加载对应的数据
Useruser=(User)session.load(User.class,pk);
System.out.println(user.getAge()+"\t"+
user.getUserPK().getName()+"\t"+
user.getUserPK().getPhone());
session.close();