-
다양한 연관관계 매핑JPA/JPA 기본 2023. 7. 11. 18:04
연관관계 매핑시 고려사항 3가지
- 다중성
- 단방향, 양방향
- 양방향일 때 연관관계 주인
다중성
- 다대일[N:1] : @ManyToOne
- 일대다[1:N] : @OneToMany
- 일대일[1:1] : @OneToOne
- 다대다[N:M] : @ManyToMany
AvsB의 구조에서 A가 연관관계 주인이다. 예를 들면 다대일에서는 다가 연관관계 주인이고, 일대다에서는 일이 연관관계 주인이다.
단방향, 양방향
테이블
- 외래 키 하나로 양쪽 조인 가능
- 사실 방향이라는 개념은 없음
객체
- 참조용 필드가 있는 쪽으로만 참조 가능
- 한쪽만 참조하면 단방향
- 양쪽이 서로 참조하면 양방향 (양방향은 서로 단방향으로 연결된 것임)
연관관계 주인
- 테이블은 외래 키 하나로 두 테이블이 연관관계를 맺음
- 객체 양방향 관계는 A->B, B->A처럼 참조가 2군데
- 객체 양방향 관계는 참조가 2군데 있음. 둘 중 테이블의 외래 키를 관리할 곳을 지정해야 함
- 연관관계의 주인 : 외래 키를 관리하는 참조
- 주인의 반대편 : 외래 키에 영향을 주지않고 단순 조회만 가능
1. 다대일[N:1] : @ManyToOne
Member와 Team의 관계가 다대일 관계이다. db의 입장에서 보면 다수인 Member 쪽이 외래키를 가지게 된다. 관계형 db에서는 항상 다수쪽이 외래키를 가지기 때문이다. 외래키가 있는 곳에 참조를 걸고 연관관계 매핑을 하는 것이 다대일 단방향 매핑이다. 가장 많이 사용하는 연관관계 매핑이다.
단방향
@ManyToOne @JoinColum(name = "TEAM_ID") private Team team;
Member에서는 Team을 참조하는 변수가 있다. 하지만 Team은 Member를 참조할 마음이 없기 때문에 Team에는 아무런 참조가 이루어지지 않는다.
양방향으로 추가
@OneToMany(MappedBy = "team") private List<Member> members = new ArrayList<>();
Team에서 매핑을 함으로써 다대일 양방향 매핑이 된다. MappedBy = "team"에 의해서 Member 객체에 있는 team이라는 변수에 매핑이 되는 것이며 테이블에 영향을 주지 않고 조회하는 것만 가능하다.
2. 일대다[1:N] : @OneToMany
일대다에서는 일이 연관관계의 주인이다. Team이 일이고 Member가 다인데, Team에서 연관관계 주인을 가지는 것이다. Team은 Member를 참조하고 싶지만, Member는 Team을 참조 하고 싶지 않을 때가 일대다 단방향이다. 하지만 관계형 db에서는 Member쪽에 항상 외래키가 있어야한다.
일대다 매핑은 일쪽에 연관관계의 주인이 있는데, 테이블에서 외래 키는 다쪽에 있다. 그렇기 때문에 쿼리가 다대일 매핑보다 한번 더 나가기도 하고, 객체와 테이블의 차이 때문에 반대편 테이블의 외래 키를 관리하는 구조이기 때문에 테이블이 많아지면 복잡해져서 다대일 매핑이 선호된다고 한다.
일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용하는 것이 권장된다.
단방향
@OneToMany @JoinColumn(name = "TEAM_ID") private List<Member> members = new ArrayList<>();
Team쪽에서 MEMBER 테이블에 있는 TEAM_ID로 연관관계 매핑을 해준다.
양방향으로 추가
@ManyToOne @JoinColum(name = "TEAM_ID", insertable = false, updatable = false) private Team team;
연관관계 매핑을 할 때에는 insertable = false와 updatable = false 옵션을 넣어주면 읽기 전용으로 매핑이 되어진다. 하지만 일대다 방향은 복잡하기때문에 위에서 말했던 것처럼 다대일 양방향을 사용하는 것을 추천한다.
3. 일대일[1:1] : @OneToOne
일대일 관계는 반대도 일대일이기 때문에 외래 키를 아무데에나 넣을 수 있다.
Member가 주 테이블이라고 가정했을 때이다. Member는 하나의 Locker를 가진다는 규칙이 있을 때, 이 관계는 일대일 매핑 관계이다. 테이블에 LOCKER_ID (FK, UNI)에서 UNI는 유니크 제약 조건으로 일대일 관계에서의 외래키라는 뜻이다.
단방향
@OneToOne @JoinColumn(name = "LOCKER_ID") private Locker locker;
@ManyToOne 때와 비슷한 상황인데, Member에 locker를 넣어주고 연관관계의 주인으로 설정해서 매핑을 한 것이다.
양방향
@OneToOne(mappedBy = "locker"); private Member member;
양방향으로 할 때에는 읽기 전용으로 매핑을 해주면 된다. 다대일과 유사하게 Member 엔티티에 있는 locker로 mappedBy를 해주면 된다.
일대일 관계에서 대상 테이블에 외래 키가 있는 경우는 사용할 수 없다. 예를 들어 LOCKER 테이블에 외래 키가 있는데 Member 엔티티 객체에 있는 locker를 연관관계 주인으로 설정할 수 없다. JPA에서 아예 지원이 되지 않기 때문에 사용할 수 없다. 양방향일 때에는 사용할 수 있다.
4. 다대다[N:M] : @ManyToMany
관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없기 때문에 연결 테이블을 추가해서 일대다, 다대일 관계로 풀어내야한다.
객체의 관점에서는 Member는 Product 리스트를 가질 수 있고, Product는 Member 리스트를 가질 수 있기 때문에 다대다 관계가 가능하다. 하지만 테이블은 다대다가 안되기 때문에 연결 테이블로 매핑을 해줘야 한다.
@ManyToMany @JoinTable(name = "MEMBER_PRODUCT") private List<Product> products = new ArrayList<>();
MEMBER_PRODUCT라는 연결 테이블을 생성한 다음에 매핑하면 되지만 다대다는 사용하지 않는 편이 좋기 때문에 그냥 알아만 두기로 한다.
@ManyToMany(mappedBy = "products") private List<MEMBER> members = new ArrayList<>();
@OneToOne 매핑과 비슷한데 중간에 테이블이 생성된다는 차이점이 있다.
다대다 매핑의 문제점
다대다 매핑은 편리해보이지만 실무에서는 사용하지 않는다. 연결 테이블은 매핑 정보만 들어가고 중간 테이블에 추가 정보를 넣을 수 없다. 예를 들어서 주문시간, 수량 같은 데이터를 넣지 못한다. 또한, 중간 테이블이 숨겨져있기 때문에 쿼리도 예상치 못한 쿼리가 나가게 된다. 그래서 다대다 매핑은 사용하지 않는다.
다대다 문제점 해결 방법
다대다 문제점을 해결하기 위해서는 연결 테이블용 엔티티를 추가해주면 된다. 연결용으로만 작동하는 연결 테이블이 아니라 연결 테이블 '엔티티'를 만들어주면 된다. 그리고 @ManyToMany를 @OneToMany와 @ManyToOne으로 풀어서 사용하면 된다.
MemberProduct라는 엔티티 생성
@Entity public class MemberProduct { @Id @GeneratedValue private Long id; @ManyToOne @JoinColumn(name = "MEMBER_ID") private Member member; @ManyToOne @JoinColumn(name = "PRODUCT_ID") private Product product; }
Member 엔티티에서 MemberProduct와 @OneToMany로 매핑
@OneToMany(mappedBy = "member") private List<MemberProduct> memberproducts = new ArrayList<>();
Product 엔티티에서도 MemberProduct와 @OneToMany로 매핑
@OneToMany(mappedBy = "product") private List<MemberProduct> memberproducts = new ArrayList<>();
이렇게 하면 중간 엔티티에서 수량과 가격 등의 정보를 추가로 넣어줄 수 있다.
'JPA > JPA 기본' 카테고리의 다른 글
즉시로딩과 지연로딩 (0) 2023.07.11 프록시 (0) 2023.07.11 상속관계 매핑 (0) 2023.07.11 연관관계 매핑 - 단방향, 양방향 연관관계 (0) 2023.07.11 영속성 컨텍스트 (0) 2023.07.11