Jin's Dev Story

[Spring Data JPA] 연관 관계 매핑 본문

Web & Android/Spring Data JPA

[Spring Data JPA] 연관 관계 매핑

woojin._. 2023. 10. 15. 09:43

1. 종류

  • 일대일(1:1) : @OneToOne
  • 일대다(1:N) : @OneToMany
  • 다대일(N:1) : @ManyToOne
  • 다대다(N:M) : @ManyToMany

2. 방향

  • 단방향
    • A 엔티티만 B 엔티티를 참조하는 것.
    • 즉, 한 쪽만 참조하는 것을 말함.
  • 양방향
    • A 엔티티와 B 엔티티가 서로를 참조하는 것.  
    • JPA 객체지향 중심 설계에서는 단방향, 양방향 존재
    • 데이터베이스 중심 설계 테이블에서 관계는 항상

 

일대일 단방향 매핑

  • 회원들은 각자 자신의 장바구니를 하나 갖고 있으며 장바구니 입장에서 봐도 자신과 매핑되는 한 명의 회원을 갖는 일대일 매핑 구조

  • 장바구니 Entity는 현재 회원 Entity에 대한 정보를 알고 있음
  • 회원 Entity에는 장바구니(Cart) Entity와 관련된 소스가 전혀 없다는 것을 확인 가능
  • 즉, 장바구니 Entity가 일방적으로 회원 Entity를 참조하고 있는 일대일 단방향 매핑

일대일 단방향 매핑 예시

1. Cart (장바구니) Entity 생성

package kr.spring.cart.entity;

import jakarta.persistence.*;
import kr.spring.member.entity.Member;
import kr.spring.utils.entity.BaseEntity;
import lombok.*;

@Entity
@Getter
@Setter
@ToString
@NoArgsConstructor
public class Cart {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "cart_id")
    private Long id;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "member_id")
    private Member member;
}

2. CartRepository

  • 장바구니 조회를 위한 Repository
import kr.spring.cart.entity.Cart;
import org.springframework.data.jpa.repository.JpaRepository;

public interface CartRepository extends JpaRepository<Cart, Long> {

}

 


다대일 단방향 매핑

  • 장바구니에는 고객이 관심이 있거나 나중에 사려는 상품들을 담아둠
  • 하나의 장바구니에는 여러 개의 상품들이 들어갈 수 있음
  • 하나의 상품은 여러 장바구니에 장바구니 상품으로 들어갈 수 있음

1. CartItem Entity 생성

import jakarta.persistence.*;
import kr.spring.item.entity.Item;
import kr.spring.utils.entity.BaseEntity;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Entity
@Getter
@Setter
@ToString
@NoArgsConstructor
public class CartItem extends BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "cart_item_id")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "cart_id")
    private Cart cart;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "item_id")
    private Item item;

    private int count;
}

양방향 매핑

  • 단방향 매핑이 2개 있는 구조 1:N ⇒ @OneToMany / N:1 ⇒ @ManyToOne
  • 현재까지는 장바구니 상품 Entity가(CartItem) 장바구니를(Cart) 참조하는 단방향 매핑
  • 장바구니 Entity에 장바구니 상품 Entity를 일대다 관계 매핑을 추가하여 양방향 매핑으로 변경 가능

  • ORDERS와 ORDER_ITEM 테이블을 ORDER_ID를 외래키로 조인하면 주문에 속한 상품이 어떤 상품들이 있는지 알 수 있고, 주문 상품은 어떤 주문에 속하는지를 알 수 있음
  • 즉, 테이블은 외래키 하나로 양방향 조회가 가능

→ 다대일과 일대다는 반대 관계

→ 주문 상품 엔티티 기준에서 다대일 매핑이었으므로 주문 엔티티 기준에서는 주문 상품 엔티티와 일대다 관계로 매핑

→ 양방향 매핑에서는 ‘연관 관계 주인’을 설정해야 한다는 점이 중요

N:1 - 1:N 관계에서  N이 주인이 됨.
→ 주로 FK를 갖는 쪽이 주인 TAG가 POST를 참조하므로 TAG 테이블이 부모 엔티티로 간주됨.

@JoinColumn

→ 양방향 연관관계에서 주인을 뜻함.

→ DB에 실제로 컬럼이 생김.

→ 조회 + 추가, 삭제, 수정이 가능함.

 

(mappedBy = )

→ 주인이 아님을 뜻함. 즉, mappedBy는 주인 엔티티의 필드명을 가리킴.

→ DB에 올라가는 컬럼이 없음.

→ 오직 조회만 가능함.

 

→ 외래키(order_id)가 order_item 테이블에 있으므로 연관 관계의 주인은 OrderItem 엔티티

→ Order 엔티티가 주인이 아니므로 “mappedBy” 속성으로 연관 관계의 주인을 설정

→ 속성의 값으로 “order”를 적어준 이유는 OrderItem에 있는 Order에 의해 관리된다는 의미로 해석

→ 연관 관계의 주인의 필드인 order를 mappedBy의 값으로 세팅


다대다 매핑

  • 실무에서 사용하지 않는 매핑
  • 관계형 데이터베이스는 정규화된 테이블 2개로 다대다를 표현할 수 없음
  • 연결 테이블을 생성해서 다대다관계를 일대다, 다대일 관계로 풀어냄

  • 객체는 테이블과 다르게 컬렉션을 사용해서 다대다 관계를 표현할 수 있음
  • item을 리스트 형태로 가질 수 있으며, item 엔티티도 member를 리스트로 가질 수 있음

  • 다대다 매핑을 사용하지 않는 이유
    • 연결 테이블에 컬럼을 추가할 수 없음
    • 추가 컬럼이 필요한 경우가 많은데 하지 못함
    • 엔티티를 조회할 때 어떤 쿼리문이 실행될지 예측하지 못함

'Web & Android > Spring Data JPA' 카테고리의 다른 글

[Spring Data JPA] 즉시로딩, 지연로딩  (0) 2023.10.15
[Spring Data JPA] 영속성 전이, 고아객체  (0) 2023.10.15
[Spring Data JPA] Querydsl  (0) 2023.10.15
[Spring Data JPA] @Query  (0) 2023.10.14
[Spring Data JPA] JPA  (0) 2023.10.14