Hibernate 无主键表(复合主键)映射
在现实中我们可能会遇到许多表可能是没有主键的,那么我们对其做映射后使用会是什么样的结果?能正常得到我们想要的吗?结果应该是得不到想要的结果,而得到的可能会是如下的报错:
Caused by:org.hibernate.AnnotationException: No identifier specified for entity: xxx.xxx.xxx
这个结果告诉我们:Hibernate映射表是需要主键的。
所以复合主键映射就应运而生了。
复合主键使用一个可嵌入的类作为主键表示,因此你需要使用@Id和@Embeddable两个注解.还有一种方式是使用@EmbeddedId注解.当然还有一种方法那就是——使用@IdClass注解。具体请查看【hibernate-annotations-3.4.0.GA 2.2.6.映射复合主键与外键】。
当然,只需要选择其中的一种就可以了。^_^
注意所依赖的类必须实现 serializable以及实现equals()/hashCode()方法.
举一个具体事例:
package com.sourcefour.bean;
// default package
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;
/**
* User entity. @author MyEclipse Persistence Tools
*/
@Entity
@Table(name="t_user_composite_pk"
)
public class User implements java.io.Serializable {
// Fields
private UserId id;
// Constructors
/** default constructor */
public User() {
}
/** full constructor */
public User(UserId id) {
this.id = id;
}
// Property accessors
@EmbeddedId
@AttributeOverrides( {
@AttributeOverride(name="intId", column=@Column(name="intId", nullable=false) ),
@AttributeOverride(name="varcName", column=@Column(name="varcName", length=50) ),
@AttributeOverride(name="varcAddress", column=@Column(name="varcAddress", length=50) ),
@AttributeOverride(name="intAge", column=@Column(name="intAge", nullable=false) ) } )
public UserId getId() {
return this.id;
}
public void setId(UserId id) {
this.id = id;
}
}
2.2. UserId.java
package com.sourcefour.bean;
// default package
import javax.persistence.Column;
import javax.persistence.Embeddable;
/**
* UserId entity. @author MyEclipse Persistence Tools
*/
@Embeddable
public class UserId implements java.io.Serializable {
// Fields
private int intId;
private String varcName;
private String varcAddress;
private int intAge;
// Constructors
/** default constructor */
public UserId() {
}
/** minimal constructor */
public UserId(int intId, int intAge) {
this.intId = intId;
this.intAge = intAge;
}
/** full constructor */
public UserId(int intId, String varcName, String varcAddress, int intAge) {
this.intId = intId;
this.varcName = varcName;
this.varcAddress = varcAddress;
this.intAge = intAge;
}
// Property accessors
@Column(name = "intId", nullable = false)
public int getIntId() {
return this.intId;
}
public void setIntId(int intId) {
this.intId = intId;
}
@Column(name = "varcName", length = 50)
public String getVarcName() {
return this.varcName;
}
public void setVarcName(String varcName) {
this.varcName = varcName;
}
@Column(name = "varcAddress", length = 50)
public String getVarcAddress() {
return this.varcAddress;
}
public void setVarcAddress(String varcAddress) {
this.varcAddress = varcAddress;
}
@Column(name = "intAge", nullable = false)
public int getIntAge() {
return this.intAge;
}
public void setIntAge(int intAge) {
this.intAge = intAge;
}
public boolean equals(Object other) {
if ((this == other))
return true;
if ((other == null))
return false;
if (!(other instanceof UserId))
return false;
UserId castOther = (UserId) other;
return (this.getIntId() == castOther.getIntId())
&& ((this.getVarcName() == castOther.getVarcName()) || (this.getVarcName() != null
&& castOther.getVarcName() != null && this.getVarcName().equals(castOther.getVarcName())))
&& ((this.getVarcAddress() == castOther.getVarcAddress()) || (this.getVarcAddress() != null
&& castOther.getVarcAddress() != null && this.getVarcAddress().equals(
castOther.getVarcAddress()))) && (this.getIntAge() == castOther.getIntAge());
}
public int hashCode() {
int result = 17;
result = 37 * result + this.getIntId();
result = 37 * result + (getVarcName() == null ? 0 : this.getVarcName().hashCode());
result = 37 * result + (getVarcAddress() == null ? 0 : this.getVarcAddress().hashCode());
result = 37 * result + this.getIntAge();
return result;
}
}
3. 可能还会出现的问题
具体来说问题就是查询出来的结果列表为‘null’(这一点我这次在我机器上测试时没有出现)。
如果出现了该问题,那么看到这一点就应该能解决问题啦,如果不出现那就更好,呵呵!
但是个人觉得这一点应该还是得说的。^_^
有时候查询出来的结果列表为‘null’,这令人很是费解,可以想下这是什么原因?
直接上原因,嘎嘎……。
原因:作为联合主键的字段理论上不应该包含可能为空的字段。
原因分析:根据原因,说明实体Bean中的某个(些)对应的表字段有空值。
解决方案:只需要将可能为空的字段不作为联合主键的一部分就可以。
说的估计晕头了吧,直接来个事例吧(个人一直觉得,例子是解释问题的最好说明)。
假设表中的varcName和varcAddress是可能为空的,其它都不可能为空,那么映射应该是这样的
User.java
……
private UserId id;
private String varcName;
private String varcAddress;
……
/*
这里加入varcName和varcAddress映射内容,嗯还是贴出来吧,反正电子档的又不怕木有地方,嘎嘎……
*/
@Column(name="varcName", length=50)
public String getVarcName() {
return this.varcName;
}
public void setVarcName(String varcName) {
this.varcName = varcName;
}
@Column(name="varcAddress", length=50)
public String getVarcAddress() {
return this.varcAddress;
}
public void setVarcAddress(String varcAddress) {
this.varcAddress = varcAddress;
}
UserId.java
……
private int intId;
private int intAge;
……
对应文档,demo及sql下载:CSDN