複合主鍵(一)


基於商務需求,您會需要使用兩個欄位來作複合主鍵,例如在T_USER資料表中,您也許會使用"name"與"phone"兩個欄位來定義複合主鍵。

在設計Java程式時,建議為複合主鍵設計一個對應的物件,無論在物件語義上,或是程式撰寫上,都可以明確知道該物件代表主鍵資訊,而當中的屬性為必填資訊。

例如,您可以設計一個UserPK類別,對應T_USER表格中的"name"與"phone"複合主鍵:
  • UserPK.java
package onlyfun.caterpillar;

import java.io.Serializable;
import javax.persistence.Embeddable;

@Embeddable
public class UserPK implements Serializable {
private String name;
private String phone;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getPhone() {
return phone;
}

public void setPhone(String phone) {
this.phone = phone;
}

@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final UserPK other = (UserPK) obj;
if ((this.name == null) ?
(other.name != null) : !this.name.equals(other.name)) {
return false;
}
if ((this.phone == null) ?
(other.phone != null) : !this.phone.equals(other.phone)) {
return false;
}
return true;
}

@Override
public int hashCode() {
int hash = 5;
hash = 73 * hash + (this.name != null ? this.name.hashCode() : 0);
hash = 73 * hash + (this.phone != null ? this.phone.hashCode() : 0);
return hash;
}
}

作為複合主鍵的類別,必須實作Serializable介面,且必須重新定義equals()與hashCode()方法,必須有無參數(預設)建構子。而在這邊您使用@Embeddable標示該類別,表示這個類別將附屬於另一個實體類別,而該實體類別可以這麼設計:
  • User.java
package onlyfun.caterpillar;

import java.io.Serializable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name="T_USER")
public class User implements Serializable {
@EmbeddedId
private UserPK userPK; // 主鍵
private Long age;

public Long getAge() {
return age;
}

public void setAge(Long age) {
this.age = age;
}

public UserPK getUserPK() {
return userPK;
}

public void setUserPK(UserPK userPK) {
this.userPK = userPK;
}
}

若要將標示為@Embeddable的類別嵌入某個實體類別中作為複合主鍵類別,則要使用@EmbeddedId標示。

在儲存User時的一個例子如下:
        UserPK pk = new UserPK();
        pk.setName("bush");
        pk.setPhone("0970123456");

        User user = new User();
        user.setUserPK(pk);
        user.setAge(new Long(35));

        EntityManager entityManager =
                JPAUtil.getEntityManagerFactory().createEntityManager();
        EntityTransaction etx = entityManager.getTransaction();
        etx.begin();
        entityManager.persist(user);
        etx.commit();
        entityManager.close();

而要載入User,則使用UserPK實例進行查詢:
        UserPK pk = new UserPK();
        pk.setName("bush");
        pk.setPhone("0970123456");

        EntityManager entityManager =
                JPAUtil.getEntityManagerFactory().createEntityManager();
        EntityTransaction etx = entityManager.getTransaction();
        etx.begin();
        User user = entityManager.find(User.class, pk);
        etx.commit();
        entityManager.close();