在實體類設計中,有時候單一欄位無法唯一標識一筆資料,必須組合多個欄位才能構成主鍵。例如「CustomerEO」實體,需要同時根據 name 與 email 來查找,只有當兩者值完全相同時,才視為同一實體。本文將詳細說明如何使用 Hibernate 註解(@IdClass)來配置複合主鍵。
首先編寫一個專門的主鍵類 CustomerPK,必須滿足以下條件:
Serializable 介面equals() 與 hashCode() 方法import java.io.Serializable;
public class CustomerPK implements Serializable {
public CustomerPK() {}
public CustomerPK(String name, String email) {
this.name = name;
this.email = email;
}
private String email;
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
@Override
public int hashCode() {
final int PRIME = 31;
int result = 1;
result = PRIME * result + ((email == null) ? 0 : email.hashCode());
result = PRIME * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
final CustomerPK other = (CustomerPK) obj;
if (email == null) {
if (other.email != null) return false;
} else if (!email.equals(other.email)) return false;
if (name == null) {
if (other.name != null) return false;
} else if (!name.equals(other.name)) return false;
return true;
}
}
關鍵點說明:
equals() 用於判斷兩個主鍵物件是否相同,EntityManager 的 find() 方法即依賴此方法。hashCode() 應盡量減少碰撞機率,上述演算法為常見實作方式。使用 @IdClass 註解指定主鍵類,並在對應的屬性 getter 方法上加上 @Id:
@Entity
@Table(name = "customer")
@IdClass(CustomerPK.class)
public class CustomerEO implements java.io.Serializable {
private Integer id;
public Integer getId() { return this.id; }
public void setId(Integer id) { this.id = id; }
private String name;
@Id
public String getName() { return this.name; }
public void setName(String name) { this.name = name; }
private String email;
@Id
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
注意事項:
@IdClass 的 value 屬性必須指向複合主鍵類(本例為 CustomerPK.class)。@Id,且型別、名稱需與主鍵類一致。完成上述設定後,即可透過主鍵物件直接查詢:
CustomerPK cpk = new CustomerPK("Janet", "janetvsfei@yahoo.com.cn");
CustomerEO instance = entityManager.find(CustomerEO.class, cpk);
這樣即能精確取得符合複合主鍵條件的實體物件。
採用 @IdClass 實現複合主鍵的優點在於:主鍵類與實體類分離,符合單一職責原則;且主鍵類可重複使用於多個實體。只要遵循「實作 Serializable、提供無參建構子、正確覆寫 equals/hashCode」三原則,即可輕鬆應對複合主鍵場景。