Search
Duplicate

다양한 연관관계 매핑

연관관계 매핑시 고려사항 3가지

다중성
다대일: @ManyToOne
일대다: @OneToMany
일대일: @OneToOne
다대다: @ManyToMany
→ 다대다는 실무에서 사용하면 안된다.
단방향, 양방향
테이블
외래 키 하나료 양쪽 조인 가능
방향이라는 개념이 없음.
객체
참조용 필드가 있는 쪽으로만 참조 가능
한 쪽만 참조하면 단방향
양쪽이 서로 참조하면 양방향
연관관계의 주인
테이블은 외래 키 하나로 두 테이블의 연관관계를 찾음
객체 양방향 관계는 A→B, B→A처럼 참조가 2군데
연관관계의 주인: 외래 키를 관리하는 참조
주인의 반대편: 외래 키에 영향을 주지않고 단순 조회(참조)만 가능

다대일(N:1)

다대일(N:1) 단방향

ERD
다대일(N:1) 단방향
가장 많이 사용하는 연관관계
다대일의 반대는 일대다

다대일 양방향

ERD
외래 키가 있는 쪽이 연관관계의 주인
양쪽을 서로 참조하도록 개발
연관관계가 주인이 아닌 쪽은 단순 조회만 가능하기에 필드만 추가해주면 된다.
@OneToMany private List<Member> members = new ArrayList<>();
Java
복사

일대다(1:N)

일(One)이 연관관계의 주인이다

→ 권장하는 방법은 아니다 실무에서도 거의 사용되지 않음.
ERD
테이블 일대다 관계는 항상 다(N) 쪽에 외래 키가 있다
객체와 테이블의 차이 때문에 반대편 테이블의 외래키를 관리하는 특이한 구조

권장하지 않는 이유

1.
테이블에서는 항상 다(N) 쪽에 외래키가 있기 때문에 패러다임 충돌이 있다.
2.
@JoinColumn을 꼭 사용해야 한다. 그렇지 않으면 조인 테이블 방식을 사용한다(중간에 테이블을 하나 추가함)
3.
실무에선 테이블이 수십개 이상 운영이 되는데, 관리 및 트레이싱이 어렵다.
→Ex) 일대다(1:N)에서 저장(save)이 될 때 양 쪽 객체를 저장한 뒤 update query를 통해 외래키 설정( 3번이나 수행)
결론: 기본은 다대일(N:1)로 구현하다 필요에 의해 양방향 다대일(N:1) 관계를 수립하도록 하자.

일대다(1:N)양방향

ERD
이런 매핑은 공식적으로는 존재하지 않는다.
@JoinColumn(insertable=false, updatable=false)
/* 팀(Team) */ public class Team{ ... @OneToMany @JoinColumn(name="TEAM_ID") private List<Member> members = new ArrayList<>(); ... } /* 멤버(Member) */ public class Member{ ... @ManyToOne @JoinColumn(name="TEAM_ID", insertable=false, updatable=false) private Team team; ... }
Java
복사
→ Member Entity의 team field가 읽기전용 field가 됐다.
읽기 전용 필드를 사용해서 양방향 처럼 사용하는 방법
다대일 양방향을 사용하자.

일대일(1:1)

주 테이블이나 대상 테이블 중에 외래 키 선택 가능
외래키에 데이터베이스 유니크 제약조건 추가
다대일 연관관계와 동일하게 외래키가 있는곳이 연관관계의 주인
연관관계의 주인이 아닌 곳에 mappedBy를 넣어준다.
정리
1.
주 테이블에 외래 키
주 객체가 대상 객체의 참조를 가지는 것처럼 주 테이블에 외래 키를 두고 대상 테이블을 찾음
객체지향 개발자 선호
JPA 매핑 편리
장점: 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인 가능
단점: 값이 없으면 외래 키에 null 허용
2.
대상 테이블의 외래 키
대상 테이블에 외래 키가 존재
전통적인 데이터베이스 개발자 선호
장점: 주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조 유지
단점: 주 테이블에는 외래키가 없기 때문에 대상 테이블이 있는지 없는지 알 수 없기 때문에 즉시로딩이 무조건 된다.

다대다(N:M)

실무에서 거의 사용하지도 않고 추천하지도 않는 연관관계
객체는 컬렉션을 사용해서 객체 2개로 다대다 관계 가능
@ManyToMany 사용
@JoinTable로 연결 테이블 지정

다대다 매핑의 한계

편리해 보이지만 실무에서 사용안함.
연결 테이블이 단순히 연결만 하고 끝나지 않음.
주문시간, 수량 같은 데이터가 들어올 수 있음.그런데 못들어옴
중간테이블에 추가적인 데이터를 넣을 수 없다는 한계점 존재.
중간 테이블이 숨겨져 있기 때문에 의도치 않은 쿼리가 생성 될 수 있음.

다대다 한계 극복

연결 테이블용 엔티티 추가(연결 테이블을 엔티티로 승격)
Ex: Order 와 Item 사이에 OrderItem 연결 테이블을 엔티티로 추가
@ManyToMany → @OneToMany, @ManyToOne
아래의 Order 테이블과 다르게 MEMBER_ID, PRODUCT_ID를 복합키로 PK 선언도 가능하지만, 새로운 프라이머리 키를 선언해서 사용하는게 조금 더 선호됨.

실전예제

엔티티

ERD

엔티티 상세

N:M 관계는 1:N, N:1로 사용하자.

Search
속성
설명 1
설명
외래 키가 참조하는 대상 테이블의 컬럼명
참조하는 테이블의 기본키 컬럼명
외래 키 제약조건을 직접 지정할 수 있다. 위 속성은 테이블을 생성할 때만 사용한다.
COUNT5
Search
속성
설명
기본값
false로 설정하면 연관된 엔티티가 항상 있어야 한다
TRUE
글로벌 페치 전략 설정
@ManyToOne = FetchType.EAGER @OneToMany = FetchType.LAZY
영속성 전이 기능을 사용한다.
연관된 엔티티의 타입 정보를 설정한다. 이 기능은 거의 사용하지 않는다. 컬렉션을 사용해도 제네릭으로 타입 정보를 알 수 있다.
COUNT5
Search
속성
설명
기본값
연관관계의 주인 필드를 선택한다.
글로벌 페치 전략 설정
@ManyToOne = FetchType.EAGER @OneToMany = FetchType.LAZY
영속성 전이 기능을 사용한다.
연관된 엔티티의 타입 정보를 설정한다. 이 기능은 거의 사용하지 않는다. 컬렉션을 사용해도 제네릭으로 타입 정보를 알 수 있다.
COUNT5