다양한 연관관계 매핑

김혁준·2024년 6월 28일

JPA

목록 보기
6/16

연관관계 매핑시 고려사항

테이블과 객체의 차이

테이블은 외래 키 하나로 양쪽 조인 가능. 방향이라는 개념이 없다
객체는 참조용 필드가 있는 쪽으로만 참조 가능 한쪽만 참조하면 단방향. 양쪽이 서로 참조하면 양방향

연관관계의 주인

테이블은 외래 키 하나로 두 테이블이 연관관계를 맺음
객체 양방향 관계는 참조가 2군데. 둘중 테이블의 외래 키를 관리할 곳을 지정해야 함
연관관계의 주인은 외래키를 관리하는 참조이고 반대편은 외래 키에 영향을 주지 않으며 단순 조회만 가능하다.

@ManyToOne

가장 많이 사용하는 연관관계
양방향의 경우 외래 키가 있는 쪽이 연관관계의 주인

@OneToMany

일대다 단반향은 일이 연관관계의 주인
테이블에서는 항상 다쪽에 외래키가 있다.
객체와 테이블의 차이 때문에 반대편 테이블의 외래 키를 관리하는 특이한 구조
연관관계 관리를 위해 추가로 UPDATE SQL을 실행한다. 그러니 일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용하자
일대다 양방향 사용 X

@OneToOne

일대일 관계 이므로 주 테이블이나 대상 테이블 중에 외래키 선택
단방향의 경우 다대일 단방향 매핑과 유사하다.
양방향의 경우 외래 키가 있는 곳이 연관관계의 주인이다. 반대편은 mappedBy 적용한다.

주 테이블에 외래 키를 넣는 경우

주 객체가 대상 객체의 참조를 가지는 것처럼 주 테이블에 외래 키를 두고 대상 테이블을 찾는다.
JPA 매핑이 편리하고 주 테이블만 조회해도 대상 테이블 조회 가능
값이 없으면 외래키에 null을 허용하는 단점이 있다.

대상 테이블에 외래 키를 넣는 경우

대상 테이블에 외래 키가 존재하는 경우인데, 주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조를 유지할 수 있다.
프록시 기능의 한계로 항상 즉시 로딩되는 단점이 있다.

@ManyToMany

관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없으므로 연결 테이블을 추가해야한다.

실무에서 사용하지 말자.

연결 테이블이 단순 연결만 하는게 아니라 다른 데이터도 들어올 수 있다.

따라서, 다대다를 사용해야하는 상황이라면 연결 테이블을 엔티티로 승격시켜서 일대다, 다대일 매핑을 하자.

실전 생각 흐름

1. 유형 파악 : 다대일인지 일대일인지 다대다인지 파악

2. 양방향 할지 단방향 할지 파악 : 양방향 할거면 연관관계 편의 메서드 필수로 추가

3. 주 테이블, 대상 테이블 파악. 다(N) 쪽이 주 테이블이고 외래키 관리. 연관관계의 주인임. 일대일의 경우 주 테이블 직접 선택.

예시

다대일(N:1)

@Entity
public class Member {
    
    @Id @GeneratedValue
    private Long id;
    
    // 멤버 오더 일대다이므로 오더가 주 테이블이고 외래키를 관리한다. 오더 쪽에 조인 컬럼으로 외래키 지정하고 그리고 양방향으로 매핑하기로 결정했으므로 멤버 쪽에서는 mappedBy로 반대 변수명 적어준다.
    // 리스트 선언시 초기화 필수
    @OneToMany(mappedBy = "member")
    private List<Order> orders = new ArrayList<>();
}

@Entity
public class Order {
   
    @Id @GeneratedValue
    private Long id;

	// 연관관계의 주인. DB에 오더 테이블에 외래키 들어감.
    @ManyToOne
    @JoinColumn(name = "member_id")
    private Member member;
}

일대일(1:1)

@Entity
public class Order {
  
    @Id @GeneratedValue
    private Long id;
    
    //1:1임
    //아무쪽에서나 외래키 가질 수 있음. 설계상 딜리버리쪽에서 외래키 가지고 있음. 그러면 딜리버리가 주 테이블임. 양방향 매핑 하기로 다짐했으므로 오더 클래스에 딜리버리 추가
    @OneToOne(mappedBy = "order")
    private Delivery delivery;
}

@Entity
public class Delivery {

    @Id @GeneratedValue
    private Long id;

    @OneToOne
    @JoinColumn(name = "order_id")
    private Order order;
}

다대다(N:N)

@Entity
public class Order {
    
    @Id @GeneratedValue
    private Long id;


    // 오더와 아이템을 다대다 매핑하기로 마음먹음. 그러면 연결 테이블을 만들어아 함. 오더아이템 클래스를 만들어서 양방향 매핑해야겠다. 그러면 오더 오더아이템 일대다 이므로 오더아이템이 다쪽이라 다쪽에 외래키가 있고 연관관계의 주인이다. 오더아이템과 양방향 매핑을 할 것이므로 오더에 오더아이템 변수를 만들고 mappedBy로 매핑
    @OneToMany(mappedBy = "order")
    private List<OrderItem> orderItems;

}

@Entity
public class Item {

    @Id @GeneratedValue
    private Long id;
	
	// 아이템에서 오더를 참조하지 않기로 설계했다. 그러면 아무것도 안적어도 된다.
}

@Entity
public class OrderItem {
   
    @Id @GeneratedValue
    private Long id;

    // 오더아이템은 중간 테이블. 오더아이템이 N쪽이므로 외래키를 여기서 관리한다. 조인컬럼으로 외래키 이름 지정한다. 이때 오더와 아이템 둘다 연결한다.
    @ManyToOne
    @JoinColumn(name = "item_id")
    private Item item;

    @ManyToOne
    @JoinColumn(name = "order_id")
    private Order order;

}

출처 : 인프런 자바 ORM 표준 JPA 프로그래밍 - 기본편

https://www.inflearn.com/course/ORM-JPA-Basic/dashboard

0개의 댓글