Post

연관 관계 매핑 (3)

🎬 Intro

@ManyToMany에 대해 알아봅시다.

✅ @ManyToMany

DB는 다대다 개념이 없기 때문에 @ManyToMany를 사용할 경우 JPA는 조인테이블을 자동으로 생성합니다. 따라서 다대다 관계가 필요할경우 @ManyToMany를 사용하기 보다는 중간 테이블을 두어서 1:N, N:1 관계로 풀어내야합니다. 예를 들어 여러 상품(책)을 주문을 할 수 있을경우 주문은 상품(책)을 여러개 가질 수 있고, 상품(책) 역시 주문이 여러번 되기 때문에 주문을 여러개 가질 수 있습니다. 이경우 주문상품이라는 중간 테이블을 두어서 이 관계를 풀어내야합니다.

📝 예제

img_1.png

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로 풀어내야 합니다.
This post is licensed under CC BY 4.0 by the author.