1. 程式人生 > >Hibernate複合主鍵的註解

Hibernate複合主鍵的註解

       最近做專案用到了Hibernate框架,採用了純面向物件的思想,使用ORM對映實體。在開發中,實體中出現了複合主鍵,不再是單一的屬性作主鍵,由於採用了註解的方式,就不再使用xml檔案進行配置了,而是直接在實體中進行註釋。

Hibernate註解規範的文件中提供了三種方法

     1. 將元件類註解為@Embeddable,並將元件的屬性註解為@Id;

     2. 將元件的屬性註解為@Embeddable;

     3. 將類註解為@IdClass,並將該實體中所有主鍵屬性註解為@Id。

這裡,我採用的是第三種方法——@IdClass,下面就是具體的程式碼,大家一塊討論一下。

       首先,需要說明的是,採用@IdClass方式,需要根據所有的主鍵屬性,建立一個主鍵類,該主鍵類包含所有的主鍵,而且,作為主鍵類,需要滿足以下要求:

    1. 主鍵類必須實現序列化介面(implements Serializable);

    2. 主鍵類必須有預設的public無引數的構造方法;

    3. 主鍵類必須覆蓋equals和hashCode方法。

主鍵類IPMapKey(為了方便演示,這裡都採用了String型別)

public class IPMapKey implements Serializable {

	/**
	 * @Fields serialVersionUID	:3176972128965536016L
	 */
	private static final long serialVersionUID = 3176972128965536016L;
	
	// 主鍵屬性
	private String ip;
	
	// 主鍵屬性
	private String examPlaceId;
	
	// 主鍵屬性
	private String examId;

	/**
	 * 無引數的public構造方法,必須要有
	 */
	public IPMapKey() {
		
	}
	
	/**
	 * 重寫了一個帶引數的構造方法
	 * @param ip
	 * @param examPlaceId
	 * @param examId
	 */
	public IPMapKey(String ip, String examPlaceId, String examId) {
		this.ip = ip;
		this.examId = examId;
		this.examPlaceId = examPlaceId;
	}
	
	public String getIp() {
		return ip;
	}

	public void setIp(String ip) {
		this.ip = ip;
	}

	public String getExamPlaceId() {
		return examPlaceId;
	}

	public void setExamPlaceId(String examPlaceId) {
		this.examPlaceId = examPlaceId;
	}

	public String getExamId() {
		return examId;
	}

	public void setExamId(String examId) {
		this.examId = examId;
	}

	public static long getSerialversionuid() {
		return serialVersionUID;
	}

	/**
	 * 覆蓋hashCode方法,必須要有
	 */
	@Override
	public int hashCode() {
		final int PRIME = 31;
		int result = 1;
		result = PRIME * result + (ip == null ? 0 : ip.hashCode());
		result = PRIME * result + (examId == null ? 0 : examId.hashCode());
		result = PRIME * result + (examPlaceId ==null ? 0 : examPlaceId.hashCode());
		return result;
	}

	/**
	 * 覆蓋equals方法,必須要有
	 */
	@Override
	public boolean equals(Object obj) {
		if(this == obj) return true;
		if(obj == null) return false;
		if(!(obj instanceof PaperKey)) return false;
		IPMapKey objKey = (IPMapKey)obj;
		if(ip.equalsIgnoreCase(objKey.ip) &&
				examId.equalsIgnoreCase(objKey.examId) && 
				examPlaceId.equalsIgnoreCase(objKey.examPlaceId)) {
			return true;
		}
		return false;
	}
}
實體類IPMap(為了方便演示,這裡都採用了String型別)
@Entity
@Table(name="TE_IPMap")
@IdClass(IPMapKey.class)
public class IPMap {

	// 主鍵,這裡需要新增@Id標記
	@Id
	@Column(name="IP")
	private String ip;
	
	@Column(name="StudentNo")
	private String studentNo;
	
	// 主鍵,這裡需要新增@Id標記
	@Id
	@Column(name="ExamPlaceId")
	private String examPlaceId;
	
	// 主鍵,這裡需要新增@Id標記
	@Id
	@Column(name="ExamId", unique=true)
	private String examId;
	
	@Column(name="AddUser")
	private String addUser;
	
	@Column(name="TimeStamp")
	private String timeStamp;
	
	@Column(name="Remark")
	private String remark;

	public String getIp() {
		return ip;
	}

	public void setIp(String ip) {
		this.ip = ip;
	}

	public String getStudentNo() {
		return studentNo;
	}

	public void setStudentNo(String studentNo) {
		this.studentNo = studentNo;
	}

	public String getExamPlaceId() {
		return examPlaceId;
	}

	public void setExamPlaceId(String examPlaceId) {
		this.examPlaceId = examPlaceId;
	}

	public String getExamId() {
		return examId;
	}

	public void setExamId(String examId) {
		this.examId = examId;
	}

	public String getAddUser() {
		return addUser;
	}

	public void setAddUser(String addUser) {
		this.addUser = addUser;
	}

	public String getTimeStamp() {
		return timeStamp;
	}

	public void setTimeStamp(String timeStamp) {
		this.timeStamp = timeStamp;
	}

	public String getRemark() {
		return remark;
	}

	public void setRemark(String remark) {
		this.remark = remark;
	}
}

       在主鍵類中,為了能使集合框架中的類(如HashMap)正常工作,必須同時覆蓋equals和hashCode方法,而且不要由於寫錯引數型別,而過載了這個方法,卻沒有覆蓋它們。

       覆蓋equals時總要覆蓋hashCode,一個很常見的錯誤根源在沒有覆蓋hashCode方法。在每個覆蓋了equals方法的類中,也必須覆蓋hashCode方法。如果不這樣做的話,就會違反Object.hashCode的通用約定,從而導致該類無法結合所有基於雜湊的集合一起正常工作,這樣的集合包括HashMap、HashSet和Hashtable。

——摘自《Effective Java》

       equals方法用於判斷傳入的物件是否相同,EntityManager通過find方法來查詢Entity時,是根據equals方法的返回值來判斷的。hashCode方法返回當前物件的雜湊碼,生成的hashCode相同的概率越小越好。