연관관계 매핑

연관 관계 매핑

  • 연관관계: 어떤 엔티티를 중심으로 보느냐에 따라 연관관계 상태가 달라짐
  • JPA에는 양방향, 단방향 관계가 존재
    1. 양방향: 두 엔티티가 서로의 엔티티를 참조
    2. 단방향: 한 쪽의 엔티티만 참조
  • 연관관계 설정이 되면 한 테이블에서 다른 테이블의 기본값을 외래키로 갖게 된다.

일대일 매핑

  • @OneToOne: 다른 엔티티 객체를 필드로 정의했을 때 일대일 연관으로 매핑하기 위해 사용
  • @JoinColumn: 매핑할 외래키 설정

단방향 매핑

@OneToOne
@JoinColumn(name = "product_number")
private Product product;
  • @JoinColumn
    • 이걸 선언하지 않으면 매핑하는 중간 테이블이 생긴다.
    • 옵션
      1) name: 의도한대로 설정하기 위해서는 name속성으로 칼럼명을 지정
      2) referencedColumnName: 외래키가 참조할 상대 테이블의 칼럼명 지정
      3) foreignKey: 외래키 제약 조건 설정 (unique, nullable 등)

  • 실행 시 즉시 로딩 + left outer join
  • @OneToOne의 fetch 전략: Eager(즉시 로딩)
    ProductDetail 객체와 Product 객체가 함께 조회 = 즉시 로딩
  • @OneToOne 어노테이션 Optional
    true (nullable) 설정 - left outer join (default)
    false (not null) 설정 시 - inner join

양방향 매핑

양쪽에서 단방향으로 서로를 매핑하는 것을 의미

  • 양쪽에서 단방향으로 매핑하니 left outer joind이 두 번 수행
    – 효율성 X
    주인 개념 등장 - 한 쪽의 테이블에서만 외래키를 바꿀 수 있도록 정함
    – 양방향으로 매핑하되 한쪽에게만 외래키를 줘야 한다!
  • mappedBy 속성 사용: 어떤 객체가 주인인가..
@OneToOne(mappedBy = "product")
@ToString.Exclude // 순환참조 제거
private ProductDetail productDetail;
  • productDetail엔티티가 product 엔티티의 주인이라는 의미
  • 양방향 연관관계 설정에서는 ToString 사용 시 순환참조 발생: @ToString.Exclude 사용

다대일, 일대다 매핑

다대일 단방향 매핑

  • 상품과 공급업체 예시
  • 공급업체 하나에서 상품 여러개 공급
  • 상품 테이블 입장에서는 다대일, 공급업체 입장에서는 일대다 관계
...
public class Product extends BaseEntity {
    ...
    @ManyToOne
    @JoinColumn(name = "provider_id")
    @ToString.Exclude // 순환참조 제거
    private Provider provider;
}
  • 일반적으로 외래키를 갖는 쪽이 주인 역할 수행 - 상품 엔티티가 공급업체 엔티티의 주인
  • 쿼리로 데이터를 저장할때 외래키 부분에는 공급업체의 id 값만 들어감

다대일 양방향 매핑

  • 공급업체를 통해 등록된 상품을 조회하기 위한 일대다 연관관계
...
public class Provider extends BaseEntity {
    ...
    @OneToMany(mappedBy = "provider")
    @ToString.Exclude // lombok에 의한 순환 참조 발생 가능성으로 설정
    private List<Product> productList = new ArrayList<>();
}
  • 여러 상품 엔티티가 포함될 수 있으므로 Collection 형식으로 필드 생성
  • OneToMany의 기본 fetch 전략은 Lazy(지연 로딩)

  • mappedBy로 설정된 필드는 칼럼에 적용 X
    양쪽에서 연관관계 설정하고 있을 때 RDBMS 형식처럼 사용하기 위해 mappedBy를 통해 외래키 관리 위임
  • Provider 엔티티는 주인이 아니여서 외래키 관리불가능
    따라서 provider 등록 후 Product에 객체를 설정하는 작업을 통해 DB에 저장
  • provider Repository를 통해 연관관계가 매핑된 Product를 가져옴

일대다 단방향 매핑

  • 상품과 상품의 카테고리 예제
    ...
    public Category {
      ...
      @OneToMany(fetch = FetchType.EAGER)
      @JoinColumn(name = "category_id")
      private List<Product> products = new ArrayList<>();
    }
    
  • 이렇게 카테고리에서 @OneToMany로 일대다 단방향 연관관계 매핑
  • 매핑의 주체가 아닌 반대 테이블에 외래키가 추가된다.
    다른 테이블에 대한 update 쿼리 발생

다대다 매핑

실무에서 거의 사용 X

  • 예시: 한 종류의 상품이 여러 생선업체 + 생산업체 한 곳이 여러 상품 생산
  • 각 엔티티 서로가 리스트를 가지는 구조
  • 교차 엔티티라고 부르는 중간 테이블을 생성해 다대다 관계를 일대다 또는 다대일 관계로 해소

다대다 단방향 매핑

...
public Producer extends BaseEntity {
    ...
    @ManyToMany
    private List<Product> products = new ArrayList<>();
}
  • @ManyToMany 어노테이션 설정
  • 리스트로 필드를 가지는 객체는 외래키를 가지지 않아 @JoinColumn은 필요 없음
  • 중간 테이블 생성되어 상품 테이블과 생선업체 태이블의 기본키를 가져와 외래키로 설정함
  • 그 중간테이블에서 연관된 엔티티의 값을 가져옴

다대다 양방향 매핑

public class Product extends BaseEntity {
    @ManyToMany
    @ToString.Exclude
    private List<Producer> producers = new ArrayList<>();
}
  • 생산업체에 대한 다대다 연관관계 매핑
  • DB 테이블 구조는 변경 X: 중간 테이블로 연관관계를 설정하기 때문
  • 이렇게 중간 테이블로 관리할 경우 예기치 못한 쿼리 발행 가능
    관리하기 힘든 포인트 발생
    ∴ 중간 테이블 생성 대신 일대다, 다대일로 연관관계를 맺을 수 있는 중간 엔티티로 승격시켜 JPA에서 관리할 수 있게 생성하는게 좋다.

영속성 전이

특정 엔티티의 영속성 상태를 변경할 때 그 엔티티와 연관된 엔티티의 영속성에도 영향을 미쳐 영속성 상태를 변경하는 것

  • @OneToOne 어노테이션의 cascade(): 영속성 전이 설정에 활용
  • 영속성 전이 타입의 종류
    1) ALL: 모든 영속 상태 변경에 대해 영속성 전이 적용
    2) PERSIST: 엔티티가 영속화할 때 연관된 엔티티도 함께 영속화
    3) MERGE: 엔티티를 영속성 컨텍스트에 병합할 때 연관된 엔티티도 병합
    4) REMOVE: 엔티티를 제거할 때 연관된 엔티티도 제거
    5) REFRESH: 엔티티 새로고침 시 연관된 엔티티도 새로고침
    6) DETACH: 엔티티를 영속성 컨텍스트에서 제외하면 연관된 엔티티도 제외

  • 엔티티 생명주기와 연관
  • cascade() 요소의 리턴 타입은 배열 형식: cascade 타입을 골라 각 상황에 적용 가능
  • 한 엔티티가 cascade 요소의 값으로 주어진 영속 상태의 변경이 일어나면 매핑으로 연관된 엔티티에도 동일한 동작이 일어나도록 전이를 발생

homebdy
homebdy 개발에 이제 막 발 담근 사람. 개발에 이제 막 발 담근 사람. 개발에 이제 막 발 담근 사람. 개발에 이제 막 발 담근 사람.
comments powered by Disqus