이 글은 김영한님의 JPA 강의 중 6장을 듣고 정리한 내용입니다 :)
강의 : 자바 ORM 표준 JPA 프로그래밍 - 기본편
교재 : 자바 ORM 표준 JPA 프로그래밍🤷♀️
연관관계 매핑 할때, 3가지를 고려하자-!
1. 다중성 결정하기
- 다대일 (주인쪽에 걸어주는 것!)
- 일대다 (일쪽에서 다를 조회하는 로직이 필요하다면 매핑 걸어줄것!)
- 일대일
- 다대다 (실무에서는 쓰지 말것)
2. 단방향, 양방향 정하기
- 테이블의 경우 : '방향'이라는 개념 없음, 그냥 외래키로 조인하면 두 테이블이 연관관계를 맺음
- 객체의 경우 : 연관관계 매핑을 객체 참조하는 방식으로 하여,참조가 2군데 있어야함 ( A->B, B->A )
⇒ 외래키를 뭐로 할지, 누가 외래키를 관리할 지 정해줘야 함
⇒ 연관관계의 주인을 만들어야함!
3. 연관관계의 주인 정해주기
: 양방향의 경우, 누가 주인(= 외래키 관리하는 쪽)인지 정해주자
다중성 4가지 종류를 알아보자!
여기서는 다대일 양방향 매핑이 중요하고, 다대다는 실무에서 안 쓴다!
일대다 @OneToMany
- 일대다 단방향 [1:N] : '일'이 연관관계의 주인임, @JoinColumn을 넣어주어야함!
- 일대다 양방향 [1:N, N:1] : 이보다는 다대일 양방향('다'쪽이 주인)을 추천한다.
만약 '일'쪽에서 외래키를 관리(주인)하겠다면 헷갈리기 때문에 비추함!
⇒ 다대일 관계에서 주인은 항상 '다' 쪽에 있으므로,
⇒ 다대일 양방향을 추천한다. '다'쪽에서 '일'쪽을 조회할 일이 없더라도, '다'를 연관관계의 주인으로 설정하자!
다만, 공식적이지는 않으나 일대다 양방향을 하고 싶으면,
@JoinColumn (insertable=false, updatable=false) 이걸 '다'쪽에 걸어주면 읽기만 할 수 있음
아래는 일대다 단방향으로, 일대다 양방향은 다대일 양방향으로 가자!
@Entity
@Getter @Setter
public class Team {
@Id @GeneratedValue
@Column(name = "TEAM_ID")
private String id;
private String name;
@OneToMany
@JoinColumn(name = "TEAM_ID")
private List<Member> members = new ArrayList<>();
}
@Entity
@Setter
@Getter
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private String id;
private String username;
}
다대일 @ManyToOne
- 다대일 단방향 [N:1] : 주인인 '다'쪽에서는 '일'쪽 참조 가능하나, 반대는 조회도 불가능!
- 다대일 양방향 [N:1, 1:N] : 서로 참조하면 주인아닌 쪽에서는 조회 가능해짐, 연관관계 편의 메소드를 만들어주면 좋음 (무한 루프 주의!)
아래는 다대일 단방향, 양방향 코드이다
@Entity
@NoArgsConstructor
@ToString(exclude = "team")
@Getter @Setter
public class Member {
@Id
@Column(name = "MEMBER_ID")
private String id;
@ManyToOne
@JoinColumn(name = "TEAM_ID") // 다 쪽에서 걸어주기
private Team team;
}
@Entity
@NoArgsConstructor
@Getter @Setter
public class Team {
@Id
@Column(name = "TEAM_ID")
private String id;
// 이걸 해주면 양방향 성립
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
}
일대일 @OneToOne
: 주 테이블이나 대상 테이블, 둘 중 어디에나 외래키 넣어도 OK!
: 일대일 양방향일때는 주인이 아닌쪽에 mappedBy 를 걸어주면 된다.
- 주 테이블에 외래키 : 객체지향 개발자들이 선호하는 방식으로, 주 객체가 대상 객체의 참조를 가지는 것 처럼 주 테이블에 외래 키를 두고 대상 테이블을 찾는다.
- 대상 테이블에 외래키 : DB쪽 개발자들이 선호하는 방식으로, 일대일에서 일대다로 변경 시 테이블 구조를 그대로 유지할 수 있다. 그러나, 지연로딩이 안 되고 즉시로딩이 된다. (나중에 자세히-!)
아래는 일대일 단방향, 양방향 코드이다
@Entity
@Getter
@Setter
public class User {
@Id @GeneratedValue
@Column(name = "user_id")
private String id;
@OneToOne
@JoinColumn(name = "locker_id")
private Locker locker;
}
@Entity
@Getter @Setter
public class Locker {
@Id @GeneratedValue
@Column(name = "locker_id")
private Long id;
// (이 파트가 없으면 단방향)
@OneToOne(mappedBy = "locker") // 이걸 걸어주고
private Member member; // 객체를 참조해주면 양방향임
}
다대다 @ManyToMany
- 객체의 경우 : 다대다 관계가 가능함
- 테이블의 경우 : 기존 테이블 두개만으로 다대다 관계를 만들수 없다.
대신에 보통은 연결 테이블을 추가하여, 일대다, 다대일로 풀어내자.
@ManyToMany → @OneToMany, @ManyToOne 이렇게 풀어내어 만들자.
다대다 관계를 매핑할때 @ManyToMany는 사용하지 않는 걸 권장하는데, 아래 그림을 참고해보자

여기서 첫번째 그림처럼 @ManyToMany사용 + 연결 테이블 생성만 하면 실무에서 복잡해진다 (연결 테이블에 다른 컬럼값들을 추가하면, 더 이상 다대다 관계로 매핑하지 못해서..???)
그렇기에 연결 테이블을 엔티티로 승격시켜주어, 다른 컬럼 값들도 추가 가능하게 하자!
따라서 두번째 그림처럼
@ManyToMany → @OneToMany, @ManyToOne 이렇게 풀어내고 + 연결 테이블용 엔티티 추가하자!
아래는 비추하는 다대일 매핑
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private String id;
@ManyToMany
@JoinTable(name = "MEMBER_PRODUCT", //연결테이블 지정
joinColumns = @JoinColumn(name = "MEMBER_ID"),
inverseJoinColumns = @JoinColumn(name = "PRODUCT_ID"))
List<Product> products = new ArrayList<Product>();
}
@Entity
public class Product {
@Id
@JoinColumn(name = "PRODUCT_ID")
private String id;
}
아래는 추천하는 @ManyToMany → @OneToMany, @ManyToOne 이렇게 풀어내고 + 연결 테이블용 엔티티(Order) 추가 코드
@Entity
public class Member {
@Id @Column(name = "MEMBER_ID")
private String id;
@OneToMany(mappedBy = "product")
private List<Order> orders;
}
@Entity // 연결 테이블용 엔티티(Order)
public class Order {
@Id
@ManyToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
@Id
@ManyToOne
@JoinColumn(name = "PRODUCT_ID")
private Product product;
}
@Entity
public class Product {
@Id @Column(name = "PRODUCT_ID")
private String id;
@OneToMany(mappedBy = "product")
private List<Member> members;
}'Back-end > JPA' 카테고리의 다른 글
| [JPA/김영한] 프록시와 지연로딩 (0) | 2022.06.23 |
|---|---|
| [JPA/김영한] 고급 매핑 (0) | 2022.06.23 |
| [JPA/김영한] 연관관계 매핑하기 (0) | 2022.06.23 |
| [JPA/김영한] 엔티티 매핑 (0) | 2022.06.23 |
| [JPA/김영한] 영속성이란 (0) | 2022.06.23 |