有时一个实体的主键可能同时为多个,例如下面使用的字典“Dictionary”实体,需要通过dictId 、dictTypeid 和cityId 来查找指定实体,当且仅当dictId 、dictTypeid 和cityId 的值完全相同时,才认为是相同的实体对象。要配置这样的联合主键,步骤如以下所示。
(1)编写一个联合主键的类DictionaryPK,代码如下。
import java.io.Serializable;
import javax.persistence.Column;
/**
* 字典表主键类(联合主键)
*
* @author ahomeeye
*/
public class DictionaryPK implements Serializable {
private static final long serialVersionUID = -1118337265519377063L;
private String dictId; // 数据标识
private String dictTypeid;// 数据类型标识
private String cityId;// 所属本地网 默认0
@Column(name = "DICT_ID")
public String getDictId() {
return dictId;
}
public void setDictId(String dictId) {
this.dictId = dictId;
}
@Column(name = "DICT_TYPEID")
public String getDictTypeid() {
return dictTypeid;
}
public void setDictTypeid(String dictTypeid) {
this.dictTypeid = dictTypeid;
}
@Column(name = "CITY_ID")
public String getCityId() {
return cityId;
}
public void setCityId(String cityId) {
this.cityId = cityId;
}
public int hashCode() {
final int PRIME = 31;
int result = 1;
result = PRIME * result + ((dictId == null) ? 0 : dictId.hashCode());
result = PRIME * result
+ ((dictTypeid == null) ? 0 : dictTypeid.hashCode());
result = PRIME * result + ((cityId == null) ? 0 : cityId.hashCode());
return result;
}
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final DictionaryPK other = (DictionaryPK) obj;
if (dictId == null) {
if (other.dictId != null)
return false;
} else if (!dictId.equals(other.dictId))
return false;
if (dictTypeid == null) {
if (other.dictTypeid != null)
return false;
} else if (!dictTypeid.equals(other.dictTypeid))
return false;
if (cityId == null) {
if (other.cityId != null)
return false;
} else if (!cityId.equals(other.cityId))
return false;
return true;
}
}
作为符合主键类,要满足以下几点要求:
1.必须实现Serializable接口。
2.必须有默认的public无参数的构造方法。
3.必须覆盖equals和hashCode方法。equals方法用于判断两个对象是否相同,EntityManger通过find方法来查找Entity时,是根据equals的返回值来判断的。本例中,只有对象的dictId 、dictTypeid 和cityId 值完全相同时或同一个对象时则返回true,否则返回false。hashCode方法返回当前对象的哈希码,生成的hashCode相同的概率越小越好,算法可以进行优化。
(2)通过@IdClass注释在实体中标注联合主键,实体代码如下。
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Table;
/**
* 系统字典数据
*
* @author ahomeeye
*/
@Entity
@Table(name = "T_DICT")
@IdClass(DictionaryPK.class)
public class Dictionary implements Serializable {
private static final long serialVersionUID = 1L;
private String dictId; // 数据标识
private String dictTypeid;// 数据类型标识
private String dictName;// 数据名称
private String dictStatus;// 数据状态
private String dictDesc;// 数据描述
private Integer dictOrder;// 序号
private String cityId;// 所属本地网 默认0
@Id
@Column(name = "DICT_ID")
public String getDictId() {
return dictId;
}
public void setDictId(String dictId) {
this.dictId = dictId;
}
@Id
@Column(name = "DICT_TYPEID")
public String getDictTypeid() {
return dictTypeid;
}
public void setDictTypeid(String dictTypeid) {
this.dictTypeid = dictTypeid;
}
@Column(name = "DICT_NAME")
public String getDictName() {
return dictName;
}
public void setDictName(String dictName) {
this.dictName = dictName;
}
@Column(name = "DICT_STATUS")
public String getDictStatus() {
return dictStatus;
}
public void setDictStatus(String dictStatus) {
this.dictStatus = dictStatus;
}
@Column(name = "DICT_DESC")
public String getDictDesc() {
return dictDesc;
}
public void setDictDesc(String dictDesc) {
this.dictDesc = dictDesc;
}
@Column(name = "DICT_INDEX")
public Integer getDictOrder() {
return dictOrder;
}
public void setDictOrder(Integer dictOrder) {
this.dictOrder = dictOrder;
}
@Id
@Column(name = "CITY_ID")
public String getCityId() {
return cityId;
}
public void setCityId(String cityId) {
this.cityId = cityId;
}
}
标注联合主键时需要注意以下几个问题。
1.@IdClass标注用于标注实体所使用主键规则的类。它的定义如下所示。
@Target({TYPE}) @Retention(RUNTIME)
public @interface IdClass {
Class value();
}
2.属性Class表示联合主键所使用的类,本例中使用DictionaryPK 这个联合主键类。
3.在实体中同时标注主键的属性。本例中在dictId、dictTypeid 和cityId 的getter方法前标注@Id,表示联合主键使用这两个属性。
(3)这样定义实体的联合主键后,通过以下代码便可以获得指定的实体对象:
DictionaryPK cpk = new DictionaryPK ("asyncTree","OperLogFunc","0");
Dictionary instance = entityManager.find(DictionaryPK .class, cpk);
参考:
http://www.blogjava.net/relax/archive/2009/09/18/295587.html