最近要處理服務的升級,主要的改變內容就是,許多的表格都要從單一欄位的 PK,改變成複數欄位的 PK。
除了資料庫的異動之外,當然就是 JPA 的 model 要做相對應的調整。
而在這個調整過程裡面,有一些小細節隨著一些小問題被挑出來,可以當作是未來在開發時的注意事項。以下是舉例說明:
這是本來的表格,Game 表格有個單獨欄位的 PK 名稱是 sn,會 auto increment;而 Photo 這個表格則有一個 FK 會關聯到這個 Game 表格;他們之間是一對多的關係(Game 1:n Photo)。
在 JPA 裡面這個關係很容易描述,如果不做雙向的關係,只需要在 Photo 這個 Entity 裡面這樣描述就可以:
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
@JoinColumn(name = "game_sn")
public Game getGame() {
return game;
}
然後當你在新增 Photo 這個物件時,把取得的 Game 物件塞給他,再丟給 JPA 就可以看到在資料庫新增成功了,這部分就不再贅述。(有機會的話再講很基本的 JPA 開發好了)
在這個時候,Game 這個 Entity 是很簡單的,而且通常我都會偷懶:
以上都運作正常,接下來我們要開始做調整,將 Game 這個表格變成是複合欄位 PK:
所以 Photo 表格跟著加上欄位,並且相對應的 FK 做調整。
這時候 JPA 的 Game Entity 要跟著改,先建立一個 GamePk 的物件,帶有兩個 property:
@Embeddable
public class GamePk implements java.io.Serializable {
private Integer sn;
@Column(name = "organization_sn")
private Integer organizationSn;
public Integer getSn() {
return sn;
}
public void setSn(Integer sn) {
this.sn = sn;
}
public Integer getOrganizationSn() {
return organizationSn;
}
public void setOrganizationSn(Integer organizationSn) {
this.organizationSn = organizationSn;
}
}
Game Entity 本來的 @Id 也要跟著改,這部分就不贅述。然後 Photo Entity 也要跟著改:
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
@JoinColumns(
{
@JoinColumn(name = "game_sn", referencedColumnName = "sn"),
@JoinColumn(name = "organization_sn", referencedColumnName = "organization_sn")
}
)
public Game getGame() {
return game;
}
簡單的說就是要變成複合欄位的樣貌。
本來的流程不變,一樣是取得 Game 物件後,塞給 Photo 物件,然後再透過 JPA 去新增一筆資料。
結果發現,Photo 表格的 game_sn 欄位與 organization_sn 欄位沒有資料新增進去;把 JPA 底層用的 Hibernate 將 SQL 列印出來,發現 SQL 的確沒要求新增資料到這兩個欄位。
所以是哪裡錯了?
是這裡,在 GamePk 的 sn property 上面,少宣告了 @Column 這個 annotation。
@Embeddable
public class GamePk implements java.io.Serializable {
@Column(name = "sn")
private Integer sn;
@Column(name = "organization_sn")
private Integer organizationSn;
public Integer getSn() {
return sn;
}
public void setSn(Integer sn) {
this.sn = sn;
}
public Integer getOrganizationSn() {
return organizationSn;
}
public void setOrganizationSn(Integer organizationSn) {
this.organizationSn = organizationSn;
}
}
在 JPA 裡面,如果你的 property 名稱剛好與資料庫表格欄位名稱相同時,其實是可以省略這個 @Column 的宣告的,而殊不知,在複合欄位 PK 這個地方,你省略了這個步驟,就導致底層的 SQL 不正確了。
Add comment