테이블 설계
다대다 연관관계를 고객이 주문한 음식(Food)과 고객(Member)을 예시로 설명하겠습니다.
- 여러 가지의 음식(Food)은 여러 명의 고객(Member)에게 주문될 수 있다.
- 음식(Food) : 고객(Member) = N : M
양방향 연관관계를 위한 추가 조건은 다음과 같습니다.
- Food Entity는 Food.memberList 필드를 통해 음식을 주문한 고객 목록(List<Member)에 접근할 수 있다.
- Member Entity는 Member.foodList 필드를 통해 고객이 주문한 음식 목록(List<Food>)에 접근할 수 있다.

Entity 관계 매핑
- Food Entity
- 다대다 양방향 연관관계에서 외래키의 주인입니다.
@Entity
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
@OneToMany(mappedBy = "food")
private List<Order> orderList = new ArrayList<>();
public void addMemberList(Member member) {
this.memberList.add(member);
}
// constructor, getter, setter, ...
}
- Member Entity
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "member")
private List<Order> orderList = new ArrayList<>();
// constructor, getter, setter, ...
}
- Orders Entity
- 다대다 양방향 연관관계에서 연결 테이블입니다.
@Entity
public class Orders {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "member_id")
private Member member;
@ManyToOne
@JoinColumn(name = "food_id")
private Food food;
// constructor, getter, setter, ...
}
- 다대다 양방향 매핑에서는 외래키의 주인(Food)에 해당하는 Entity에 연결(Orders) Entity를 Collection 프레임워크로 감싼 형태의 참조 필드로 작성합니다.
- 이 때 참조 필드 위에
@OneToMany(mappedBy = "{연결(Orders) Entity가 참조하는 필드 이름}")
애노테이션을 추가로 작성합니다. mappedBy
속성은 양방향 연관관계에서 사용하며, 이 연관관계에 대해 외래 키의 주인이 참조하고 있는 필드 명을 넣어줍니다.- 마찬가지로 외래키의 주인의 반대편(Member)에 해당하는 Entity에도 연결(Orders) Entity를 Collection 프레임워크로 감싼 형태의 참조 필드로 작성하며,
@OneToMany(mappedBy = "{연결(Orders) Entity가 참조하는 필드 이름}")
을 추가로 작성합니다. - 마지막으로 연결(Orders) Entity의 참조 필드 위에 각각
@ManyToOne
애노테이션과@JoinColumn(name = "{foreign key name}")
애노테이션을 추가로 작성합니다. - 위의 Entity 관계를 적용하여 테이블을 생성하였을 때, 실행되는 SQL은 아래와 같습니다.
CREATE TABLE FOOD (
ID BIGINT NOT NULL AUTO_INCREMENT,
NAME VARCHAR(255),
PRICE FLOAT(53) NOT NULL,
PRIMARY KET (ID)
);
CREATE TABLE MEMBER (
ID BIGINT NOT NULL AUTO_INCREMENT,
NAME VARCHAR(255),
PRIMARY KET (ID)
);
CREATE TABLE ORDERS (
ID BIGINT NOT NULL AUTO_INCREMENT,
FOOD_ID BIGINT NOT NULL,
MEMBER_ID BIGINT NOT NULL
);
ALTER TABLE ORDERS
ADD CONSTRAINT FK5g4j2r53ncoltplogbnqlpt30
FOREIGN KEY (FOOD_ID)
REFERENCES FOOD (ID)
ALTER TABLE ORDERS
ADD CONSTRAINT FKpktxwhj3x9m4gth5ff6bkqgeb
FOREIGN KEY (MEMBER_ID)
REFERENCES MEMBER (ID)
Entity 관계 사용법
- 저장
@Transactional
@SpringBootTest
public class ManyToManyTest {
@Autowired FoodRepository foodRepository;
@Autowired MemberRepository memberRepository;
@Autowired OrderRepository orderRepository;
@Test
@Rollback(value = false)
@DisplayName("N대M 단방향 저장 테스트")
void OneWaySaveTest() {
// 고객(Member)
Member member = new Member("Inyong");
memberRepository.save(member);
// 음식(Food)
Food food = new Food("후라이드 치킨", 15000);
foodRepository.save(food);
// 주문(Order)
Order order = new Order();
order.setMember(member); // 외래 키(연관관계) 설정
order.setFood(food); // 외래 키(연관관계) 설정
orderRepository.save(order);
}
}
- 위 코드 실행 시, 적용되는 SQL은 다음과 같습니다.
INSERT INTO MEMBER (NAME) VALUES ('Inyong');
INSERT INTO FOOD (MEMBER_ID, NAME, PRICE) VALUES (NULL, "후라이드 치킨", 15000);
INSERT INTO ORDERS (FOOD_ID, MEMBER_ID) VALUES (1, 1);
- 조회
@Transactional
@SpringBootTest
public class ManyToManyTest {
@Autowired FoodRepository foodRepository;
@Autowired MemberRepository memberRepository;
@Autowired OrderRepository orderRepository;
@Test
@DisplayName("N대M 양방향 조회 테스트")
void TwoWayViewTest() {
// 1번 주문 조회
Order order = orderRepository.findById(1L).orElseThrow(NullPointerException::new);
// order 객체를 사용하여 고객 정보 조회
Member member = order.getMember();
System.out.println("user.getName() = " + member.getName());
// order 객체를 사용하여 음식 정보 조회
Food food = order.getFood();
System.out.println("food.getName() = " + food.getName());
System.out.println("food.getPrice() = " + food.getPrice());
}
}
// 실행 결과
// user.getName() = Inyong
// food.getName() = 후라이드 치킨
// food.getPrice() = 15000.0
- 위 코드 실행 시, 적용되는 SQL은 다음과 같습니다.
SELECT o.ID, f.ID, f.NAME, f.PRICE, m.ID, m.NAME FROM ORDERS o
LEFT JOIN FOOD f ON f.ID = o.FOOD_ID
LEFT JOIN MEMBER m ON m.ID = o.MEMBER_ID
WHERE o.ID = 1
'JPA' 카테고리의 다른 글
[JPA] 다대다 연관관계 (단방향) (0) | 2023.04.29 |
---|---|
[JPA] 일대다 연관관계 (단방향) (0) | 2023.04.29 |
[JPA] 다대일 연관관계 (양방향) (0) | 2023.04.29 |
[JPA] 일대일 연관관계 (양방향) (0) | 2023.04.29 |
[JPA] 다대일 연관관계 (단방향) (0) | 2023.04.29 |
댓글