1. JPA에서의 양방향 매핑이란
토이 프로젝트로 진행한 '여행과 여정을 기록하는 SNS 서비스' 프로젝트를 마치고, JPA를 능숙하게 다루기 위해서 공부를 하고 있다.
혼동하기 쉬운 개념을 정리하고자 포스팅을 한다.
여행과 여정은 1 : n 관계이다. DB에서는 방향을 설정해주지 않아도 FK를 활용한 조인으로 여행 테이블에서 여정테이블을 접근할 수 있고, 여정 테이블에서 여행테이블에 접근할 수 있다.
하지만 JPA는 ORM(Object Realtionial Mapping) 즉, DB의 테이블을 객체의 클래스로 매핑한 기술이기 때문에 DB와 같은 개념으로 생각하면 안된다.
JPA는 양방향 매핑이 DB처럼 양방향 관계가 설정되어 있는 것이 아니다. 아래 그림 처럼 객체의 참조를 통한 2개의 단방향 매핑을 양방향 매핑처럼 보이게 하는 것이다.
2. 양방향 매핑에서 연관관계의 주인
JPA의 양방향 매핑에서 중요한 것은 연관관계의 주인이다.
엔티티를 양방향으로 매핑하면 각 엔티티마다 반대쪽 엔티티의 인스턴스를 필드로 가져서 참조를 해야 하기 때문에, 참조는 둘인데 외래키는 하나이다. 그래서 어떤 엔티티가 외래키를 관리해야 할 지를 정해야 한다. 그래서 외래키를 관리할 책임을 가질 연관관계의 주인을 설정해야 한다.
결론은 일대다 관계에서 항상 다 쪽이 연관관계의 주인이다.
Team 엔티티는 컬렉션으로 Member의 리스트를 가지고 있다. Team 엔티티가 연관관계의 주인이 되어 외래키를 관리할 책임을 가진다면 물리적으로 다른 Member 엔티티의 외래키를 관리하는 셈이 된다. 그렇기 때문에 외래키를 등록하고 삭제할 수 있는 권한을 가진 연관관계의 주인은 일대다 관계에서 다 쪽이 된다.
mappedBy라는 어노테이션을 사용한 클래스는 연관관계의 주인이 아님을 나타낸다.
양방향 연관관계에서는 연관관계의 주인에게 값을 입력하거나, 주인 혹은 주인이 아닌쪽 모두 입력해야 한다.
연관관계의 주인만이 외래키의 값을 변경할 수 있기 때문이다.
여정은 연관관계의 주인으로써 여행ID를 외래키로 가지고 있다.
그러면 여정을 등록할때는 연관관계의 주인인 여정 엔티티만이 외래키인 trip_id 의 값을 변경할 수 있으므로, 여정 엔티티를 통해서 등록해야 한다.
3. 연관관계의 주인을 통한 생성 / 주인이 아닌쪽을 통한 생성 비교
첫 번째로 기존방식이다. 여정이 연관관계의 주인이고 여정 엔티티를 통해 여정을 등록한다.
tripId를 PathVariable로 받아서, Service계층의 메서드에 RequestDto와 함께 tripId를 파라미터로 넘긴다.
tripId로 먼저 여행을 조회한다음 해당되는 여행이 있으면 여정 엔티티에 add메서드를 통해 추가하는 로직이 수행된다.
add메서드는 setter를 사용하지 않기 위해서 따로 정의한 메서드이다.
만약에 여행엔티티를 통해서 등록하게 되면 어떻게 될까?
현재 1번 여행에 대한 여정이 총 3개가 등록되어 있는 상태이다.
tripId로 여행을 먼저 조회한 이후 여정 엔티티에 추가하는 것이 아니라, 여행 엔티티가 필드로 가지고 있는 여정의 리스트에 추가했다.
밑에 테스트용으로 출력을 해보았다.
모두 Null이다...
결론은 외래키를 가진 엔티티, 즉 연관관계의 주인 엔티티를 통해 값을 추가해야 한다.
'Spring' 카테고리의 다른 글
[JPA] fetchType.EAGER(즉시로딩)의 N+1문제의 원인과 해결방법 (1) | 2023.11.09 |
---|---|
[JPA] 즉시로딩과 지연로딩 (1) | 2023.11.08 |
예외처리 - Exception Handle (0) | 2023.10.28 |
[SpringBoot] BindException 해결법 (0) | 2023.08.26 |
MySQL 테이블 생성 및 스프링 db 연동 (0) | 2023.08.24 |