🎬 Intro
@ManyToMany에 대해 알아봅시다.
✅ @ManyToMany
DB는 다대다 개념이 없기 때문에 @ManyToMany를 사용할 경우 JPA는 조인테이블을 자동으로 생성합니다. 따라서 다대다 관계가 필요할경우 @ManyToMany를 사용하기 보다는 중간 테이블을 두어서 1:N, N:1 관계로 풀어내야합니다. 예를 들어 여러 상품(책)을 주문을 할 수 있을경우 주문은 상품(책)을 여러개 가질 수 있고, 상품(책) 역시 주문이 여러번 되기 때문에 주문을 여러개 가질 수 있습니다. 이경우 주문상품이라는 중간 테이블을 두어서 이 관계를 풀어내야합니다.
📝 예제
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
| @Entity
@Table
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Data
public class Card {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String number;
@OneToOne(mappedBy = "card", fetch = FetchType.LAZY)
private Customer customer;
@Builder
public Card(final Long id, final String number, final Customer customer) {
this.id = id;
this.number = number;
this.customer = customer;
}
// 연관관계 편의 메서드
public void updateCustomer(final Customer customer) {
customer.setCard(this);
this.customer = customer;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| @Entity
@Table
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Data
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "card_id")
private Card card;
@Builder
public Customer(final Long id, final String name, final Card card) {
this.card = card;
this.id = id;
this.name = name;
}
}
|
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
| @Entity
@Table
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Data
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String author;
@ManyToOne
@JoinColumn(name = "book_store_id")
private BookStore bookStore;
@Builder
public Book(final Long id, final String title, final String author) {
this.id = id;
this.title = title;
this.author = author;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| @Entity
@Table
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Data
public class BookStore {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@Builder
public BookStore(final Long id, final String name) {
this.id = id;
this.name = name;
}
}
|
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
| @Entity
@Table
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Data
public class Orders {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "customer_id")
private Customer customer;
@OneToMany(mappedBy = "orders")
private List<OrderBook> orderBooks = new ArrayList<>();
@Enumerated(value = EnumType.STRING)
private OrderStatus status;
public void addOrderBook(final OrderBook orderBook) {
orderBook.setOrders(this);
this.orderBooks.add(orderBook);
}
@Builder
public Orders(final Customer customer) {
this.customer = customer;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| @Entity
@Table
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Data
public class OrderBook {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "orders_id")
private Orders orders;
@ManyToOne
@JoinColumn(name = "book_id")
private Book book;
private int quantity;
}
|
1
2
3
4
5
6
7
8
9
10
11
| package com.example.jparemind1.domain;
public enum OrderStatus {
PENDING, // 주문 접수 대기 중
CONFIRMED, // 주문 확정
CANCELED, // 주문 취소
RETURNED; // 반품
}
|
- 고객은 하나의 카드만 소지할 수 있습니다. 따라서 Customer와 Card는 1:1 단방향 관계 입니다. 외래키는 Customer에 존재하고 연관관계 주인입니다. 만약 Card객체에서 Custmomer에 정보를 조회할 일이 많다면 양방향으로 설정합니다.
- Book 과 BookStore는 N:1 단방향 관계 입니다. Book이 N이므로 외래키는 Book에 존재하며 연관관계 주인입니다.
- 하나의 주문은 여러을 주문할 수 있고 책 역시 여러번 주문 될 수 있습니다. 따라서 Orders와 Book은 N:N 관계 입니다. OrderBook 이라는 중간 테이블을 두어 이를 1:N N:1로 풀어냅니다.
- Orders와 OrderBook 1:N 양방향 관계 입니다. Orders 에서 주문 책들을 조회하는 일이 많아 Orders 객체에서도 OrderBook 객체를 조회 할 수 있게끔 양방향으로 설정합니다. N쪽인 OrderBook에 외래키가 존재하고 연관관계 주인입니다.
- OrderBook과 Book은 N:1 단방향 관계입니다. Book 쪽에서 OrderBook을 조회할 일이 거의 없어 단방향으로 설정합니다. N쪽인 OrderBook에 외래키가 존재하고 연관관계 주인입니다.
✨ Summary
- @ManyToMany는 N:N 관계이며 DB상에는 존재하지 않습니다. 따라서 사용을 지양하고 중간 테이블을 두어서 1:N N:1로 풀어내야 합니다.