본문 바로가기

개발/Spring

[JPA] 연관관계 설정 예시

 

1. 예제

  • 참조를 할 때 주인을 정해야 한다.
  • 양방향 참조 시 양쪽에서 데이터가 변경되면 JPA가 어떤 데이터를 따라야 하는지 혼란

Entity
table

 

2. N:1 양방향

  • Order와 Member가 N:1 양방향 참조를 할 때
    • 외래키를 가진 쪽이 연관관계 주인이 된다.
    • 주인을 정할 때 유의해야할 것은 비즈니스 적으로 생각하지 말고 데이터의 흐름과 관리, 유지보수를 고려하여 정한다.
    • 양방향 참조는 실무에서 잘 쓰지 않는다.
  • N:1 양방향 연관관계 설정 코드를 살펴보자
    • Order Entity
@Entity
@Table(name="orders")
@Getter @Setter
public class Order {

    @Id @GeneratedValue
    @Column(name = "order_id")
    private Long id;

    @ManyToOne
    @JoinColumn(name = "member_id")
    private Member member;

}
  • Member Entity
@Entity
@Getter @Setter
public class Member {

    @Id @GeneratedValue
    @Column(name = "member_id")
    private Long id;

    private String name;

    @Embedded // 내장타입 명시
    private Address address;

    @OneToMany(mappedBy = "member") // 연관관계의 거울, member 필드에 의해 매핑 된다.
    private List<Order> orders = new ArrayList<>();
}

 

3. 상속 관계

  • 예제에서 Item은 Book + Movie + Album과 상속 관계
  • 상속관계 전략 3가지
public enum InheritanceType { 

    /** A single table per class hierarchy. */
    SINGLE_TABLE, 

    /** A table per concrete entity class. */
    TABLE_PER_CLASS, 

    /** 
     * A strategy in which fields that are specific to a 
     * subclass are mapped to a separate table than the fields 
     * that are common to the parent class, and a join is 
     * performed to instantiate the subclass.
     */
    JOINED 
}
  • 예제에서는 SINGLE_TABLE 설정을 사용
  • dtype 컬럼으로 구분한다.
  • 부모 Entity를 추상클래스로 생성
  • 상속관계 설정을 코드로 살펴보자
    • Item Entity
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "dtype") // 자식 객체 구분 기준 컬럼
@Getter @Setter
public abstract class Item {

    @Id @GeneratedValue
    @Column(name = "item_id")
    private Long id;

    private String name;
    private int price;
    private int stockQuantity;
}
  • Book Entity
@Entity
@DiscriminatorValue("B") // Item의 dtype에 들어갈 album 객체의 타입 값
@Getter @Setter
public class Book extends Item{

    private String author;
    private String isbn;
}

 

4. 1:1 관계

  • 외래키를 가진 쪽이 주인이 된다.
  • Order와 Delivery에서 Order가 주인
  • 1:1 관계 설정을 코드로 살펴보자
    • Order Entity
@OneToOne // 1:1 관계
@JoinColumn(name = "delivery_id")
private Delivery delivery;
  • Delivery Entity
@Entity
@Getter @Setter
public class Delivery {

    @Id
    @GeneratedValue
    private Long id;

    @OneToOne(mappedBy = "delivery")
    private Order order;

    @Embedded
    private Address address;

    @Enumerated(EnumType.STRING) // ORDINAL로 설정하면 값이 추가되거나 순서가 바뀌면 기존 값이 바뀌어 장애 발생
    private DeliveryStatus ststus; // READY, COMP
}

 

5. N:N 관계

  • 실무에서는 절대 사용하지 않는다.
  • 테이블에서는 1:N, N:1 관계가 되도록 중간 테이블이 필요
  • 예제의 Category와 Item 관계
  • N:N 관계 코드
    • Category Entity
@Entity
@Getter @Setter
public class Category {

    @Id @GeneratedValue
    @Column(name = "category_id")
    private Long id;

    private String name;

    @ManyToMany
    @JoinTable(name = "category_item",
            joinColumns = @JoinColumn(name = "category_id"),
            inverseJoinColumns = @JoinColumn(name = "item_id")) // 다대다 관계에서는 중간 테이블 매핑 필요
    private List<Item> items = new ArrayList<>();
}
  • Item Entity
@ManyToMany(mappedBy = "items")
    private List<Category> categories = new ArrayList<>();

 

6. 번외) 자신을 참조할 때

  • Categoty에서 계층구조를 만들어야 할 때
  • 예) 가전 - 컴퓨터 - 키보드
  • 코드
    • Category Entity
// 카테고리의 계층 구조 설정, 자신을 참조할 때
@ManyToOne
@JoinColumn(name = "parent_id")
private Category parent;

@OneToMany(mappedBy = "parent")
private List<Category> child = new ArrayList<>();

'개발 > Spring' 카테고리의 다른 글

[JPA] flush(), clear()  (0) 2023.03.28
[JPA] API 조회 기능 개발 정리  (0) 2023.03.28
[JPA] 게시글 1000만건 처리하기  (0) 2022.11.03
[SpringBoot] MariaDB 연동 / querydsl 설정  (0) 2022.10.12
[SpringBoot] 데이터 조회  (0) 2022.09.14