https://ithelp.ithome.com.tw/upload/images/20240904/20150977s7zH4hK4Ja.png

一對多 1 : N

一對多關聯可以看到,products 和 reviews 這兩張表的關係,一個商品會有多則評論,所以設計上會在 reviews 裡面紀錄 product_id 來關聯回去 products。會應用到 @OneToMany @ManyToOne 這兩種註解來根據你是哪一方進行關聯。

建立父實體 reviews,標記 @ManyToOne

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Entity
@Data
@Table(name = "reviews")
@JsonIgnoreProperties({"product"})
public class Review {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String comment;
private int rating;

@ManyToOne
@JoinColumn(name = "product_id", referencedColumnName = "id")
private Product product;
}

注意 reviews 是多的那邊所以用 @ManyToOne ,和一對一配置相同,如果是父實體就會用上 @JoinColumn 並且標出 FK 的欄位。

建立子實體 products,標記 @OneToMany

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Entity
@Data
@Table(name = "products")
//@JsonIgnoreProperties({"productDetail"})
//@JsonIgnoreProperties({"reviews"})
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;
private Double price;
private String description;

@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "product_detail_id", referencedColumnName = "id")
private ProductDetails productDetails;

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "product")
private List<Review> reviews;
}

這邊也配置雙向關聯回去,但是要記得使用 @JsonIgnoreProperties 來指定某些屬性不要序列化成 Json 避免雙向循環,假設你是純粹要把關聯用再查 Review 時可以帶出關聯的 Product 就可以不用在 Product 的 Entity 寫 @OneToMany 的部分,但如果要從 Product 關聯回去 Review 就必須兩邊都綁定,因為 Product 在這邊屬於被子實體,要 mappedBy 確定父實體的關聯屬性,沒辦法單方向關聯回去。

這邊我們讓 Product 可以關聯回去 Review 所以可以查到下面這樣

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
[
{
"id": 1,
"name": "最後生還者",
"price": 59.99,
"description": "由 Naughty Dog 開發的動作冒險遊戲。",
"productDetails": {
"id": 1,
"developer": "Naughty Dog",
"publisher": "Sony Interactive Entertainment",
"releaseDate": "2013-06-14",
"languageSupport": "English, Japanese, Chinese"
},
"reviews": [
{
"id": 1,
"comment": "這是一款令人驚嘆的遊戲,擁有引人入勝的故事和令人驚嘆的視覺效果!",
"rating": 5
},
{
"id": 11,
"comment": "遊戲不錯,但希望戰鬥系統能更具挑戰性。",
"rating": 4
},
{
"id": 12,
"comment": "每一秒鐘都充滿樂趣,真的是一款精緻的遊戲!",
"rating": 5
}
]
},
{
"id": 2,
"name": "巫師3",
"price": 49.99,
"description": "由 CD Projekt Red 開發的開放世界角色扮演遊戲。",
"productDetails": {
"id": 2,
"developer": "CD Projekt Red",
"publisher": "CD Projekt",
"releaseDate": "2015-05-19",
"languageSupport": "English, Chinese, Polish"
},
"reviews": [
{
"id": 2,
"comment": "很棒的遊戲,但某些部分的節奏感覺有點慢。",
"rating": 4
},
{
"id": 13,
"comment": "畫質很好,但劇情有點單調。",
"rating": 3
}
]
}
// ......略
]

關於一對多的設置上其實跟一對一很類似,主要都是要區別出哪個是父實體和子實體,一開始規劃資料表時就可以根據此來配置關聯的欄位,實際撈取資料上也要根據需求決定是否需要雙向關聯,回傳的資料上也可以採用 DTO 的方式可以回傳需要的欄位,中間實作上也要避免雙向循環,這樣就可以好好應用這些關聯方式,下一篇來介紹多對多的部分。

Ref: