複合主鍵定義需求
- 主鍵類別必須實作
equals()、hashCode()
- 需實作
Serializable
- 提供無參建構子
- 標註
@IdClass 或 @EmbeddedId
方案一:@IdClass(主鍵類別獨立)
public class NamePK implements Serializable {
private String first, last;
// equals/hashCode
}
@Entity @IdClass(NamePK.class)
public class Student implements Serializable {
@Id @Column(name="FIRST") private String first;
@Id @Column(name="LAST") private String last;
// 其他屬性...
}
方案二:@EmbeddedId(主鍵內嵌)
@Embeddable
public class NamePK implements Serializable {
@Column(name="FIRST") private String first;
@Column(name="LAST") private String last;
// equals/hashCode
}
@Entity
public class Student implements Serializable {
@EmbeddedId private NamePK namePK;
// 其他屬性...
}
兩者差異比較
| 維度 | @IdClass | @EmbeddedId |
| 主鍵屬性在實體中 | 獨立欄位,重複定義 | 單一嵌入物件 |
| 查詢 API | em.find(Student.class, new NamePK("a","b")) | 相同 |
| JPQL 存取 | s.first, s.last | s.namePK.first, s.namePK.last |
| 適用場景 | 既有資料表、需單獨存取主鍵欄位 | 新設計、領域模型導向 |
完整範例(採 @IdClass)
@DependentObject public class Name implements Serializable {
private String first, last;
// equals/hashCode 實作
}
@Entity @Table(name="STUDENT") @IdClass(Name.class)
public class Student implements Serializable {
@Id @Column(name="FIRST") public String getFirst() { return name.getFirst(); }
@Id @Column(name="LAST") public String getLast() { return name.getLast(); }
// ...
}
Client 驗證
Name pk = new Name("朱", "立煥");
Student s = dao.find(pk); // 透過複合主鍵查詢