개요
기존 포스팅 최하단에 비고로 테이블 중심 설계가 아닌 객체 중심으로 설계할 경우 발생할 수 있는 문제에 대해 살짝 언급했었습니다. (https://jaimemin.tistory.com/1899)
이번 게시글에서는 연관관계 매핑에 대해 간단하게 알아보고 왜 테이블 중심으로 설계해야 하는지 이해해보겠습니다.
1. 객체 중심으로 모델링할 경우 문제점
- 객체를 테이블에 맞추어 모델링할 경우 참조 대신 외래 키 즉, Foreign Key를 그대로 사용
- 이럴 경우 외래 키 식별자를 직접 다루는 것이 문제
- 식별자를 직접 다루기 때문에 식별자로 다시 조회하는 상황이 발생하는데, 이런 방식은 객체지향적이지 않음
- 정리를 하자면, 객체를 테이블에 맞추어 데이터 중심으로 모델링할 경우 협력 관계를 만들어낼 수 없음
- 테이블은 Foreign Key로 Join을 통해 연관된 테이블을 찾아내고 객체는 참조를 통해 연관된 객체를 찾기 때문에 이러한 문제점이 발생
예제: 직원을 나타내는 클래스가 있고 해당 직원은 어떤 기업의 소속
기업과 직원을 등록하고 다시 조회하는 코드 (연관관계 X)
2. 단방향 연관관계 (객체 연관관계 사용)
- 기존 예제에서 사용한 직원, 회사 엔티티에 연관관계를 입혀보면
- 회사에는 많은 직원들이 있고 대부분의 회사들은 겸업을 금지하므로 직원 : 회사 = N : 1
- 기존에는 Foreign Key를 그대로 사용하는 것이 문제였으므로 이번에는 객체의 참조를 이용하고 이에 맞는 JPA 어노테이션을 적용 (@ManyToOne, @JoinColumn)
- 연관관계를 적용함에 따라 직원 객체로부터 바로 기업을 찾아낼 수 있는 것을 확인할 수 있음
예제: 직원을 나타내는 클래스가 있고 해당 직원은 어떤 기업의 소속
기업과 직원을 등록하고 다시 조회하는 코드 (연관관계 O)
3. 양방향 연관관계
- 단방향 연관관계 예제에서는 기업 엔티티를 통해 소속된 직원들을 찾을 수 없었지만
- 양방향 연관관계를 적용할 경우 직원 엔티티를 통해 기업을 찾을 수도 있고 적절한 JPA 어노테이션을 통해 기업 엔티티를 통해 소속된 직원들을 찾을 수 있음 (@OneToMany, )
예제: 직원을 나타내는 클래스가 있고 해당 직원은 어떤 기업의 소속
기업과 직원을 등록하고 다시 조회하는 코드 (연관관계 O)
3.1 양방향 연관관계 = 단방향 연관관계 * 2
- 객체와 테이블 간에 연관관계를 맺는 차이를 이해하는 것이 핵심
- 단방향 연관관계의 경우 연관관계가 2개 (직원 > 기업, 기업 > 직원)
- 양방향 연관관계의 경우 논리적으로는 연관관계가 1개 (직원 <-> 기업)
- 하지만, 사실 양방향 관계는 서로 다른 단방향 관계가 2개인 상태
- 따라서 객체를 양방향으로 참조하기 위해서는 단방향 연관관계를 2개 만들어야 함
3.2 테이블의 양방향 연관관계
- 테이블은 외래 키, Foreign Key 하나를 통해 두 테이블의 연관관계를 맺음
- 앞선 예제에서는 COMPANY 테이블의 COMPANY_ID 외래 키 하나를 통해 양방향 연관관계를 가짐
SELECT *
FROM EMPLOYEE
INNER JOIN COMPANY
ON EMPLOYEE.COMPANY_ID = COMPANY.COMPANY_ID
3.3 양방향 연관관계의 주인과 mappedBy 속성
- 앞선 예제에서 외래 키인 COMPANY_ID를 통해 양방향 연관관계를 가지므로 DB 입장에서는 Employee 내 Foreign Key만 관리해주면 됨
- Employee 내 외래 키를 바꾸면 다른 기업을 참조
- DB 입장에서는 양방향 연관관계 중 하나의 객체를 주인으로 지정하여 외래 키를 등록 및 수정하게 하는 것이 관리 측면에서 효율적
- 주인이 아닌 쪽은 등록 및 수정이 불가하고 오로지 읽기만 가능
- 읽기만 가능한 객체는 mappedBy 속성을 사용하고 등록 및 수정이 가능한 주인은 mappedBy 속성을 사용하지 않음
- 정리를 하자면, 외래 키가 있는 객체 즉, Many 쪽을 무조건 연관관계의 주인으로 정하자
- 비즈니스 로직을 기준으로 연관관계의 주인을 선택 X
- 위 에제에서는 직원이 Many이므로 직원인 Employee 객체가 양방향 연관관계의 주인
- 이론상 연관관계의 주인 쪽에만 연관관계를 맺은 객체를 넣어주면 되지만 순수한 객체 관계를 고려했을 때는 양쪽 객체에 모두 값을 입력해주는 것이 맞음 (테스트 케이스 작성할 때 훨씬 수월함)
* 양방향 매핑 시 toString(), lombok, JSON 생성 라이브러리를 사용할 경우 무한 루프가 발생할 수 있으므로 주의
비고
- 앞서 JSON 생성 라이브러리를 사용할 경우 양방향 관계에서 무한 루프가 발생할 수 있다고 언급했지만 Controller에서 Entity를 직접 반환하지 않을 경우 문제 될 게 없음
- Controller에서 Entity를 직접 반환할 경우 무한루프 위험뿐만 아니라 필드 추가/삭제 시 API 스펙이 바뀔 수 있으므로 절대 Entity를 그대로 반환 X
- 추천하는 방법은 별도 DTO를 생성해서 Entity를 API 스펙에 맞는 DTO로 변환 후 Controller에서 반환하는 방법
- 양방향 매핑에 대해 알아봤지만 사실 단방향 매핑으로도 이미 연관관계는 완성된 상태
- 우선, 단방향 매핑을 기준으로 DB를 설계한 이후
- 단순 조회 기능을 목적으로 필요시 양방향 연관관계를 맺는 것을 추천
- 현업에서는 JPQL 쿼리가 너무 복잡해질 경우 양방향 연관관계를 맺는 경우가 많음
출처
자바 ORM 표준 JPA 프로그래밍 - 기본편 (김영한 강사님)
반응형
'DB > JPA' 카테고리의 다른 글
[JPA] 상속관계 매핑 (2) | 2021.09.07 |
---|---|
[JPA] 다양한 연관관계 매핑 (0) | 2021.08.31 |
[JPA] Entity 매핑 정리 (0) | 2021.08.23 |
[JPA] PersistenceContext 간단 정리 (0) | 2021.08.20 |
JPA를 학습해야하는 이유 (1) | 2021.08.16 |