ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JPA - @ElementCollection
    🌱 spring 2022. 11. 2. 17:49

    값 타입 컬렉션


    값 타입 컬렉션이란 컬렉션에 값 타입을 담는 것을 의미한다

    • 연관관계 매핑에서 엔티티를 컬렉션으로 사용하는 것이 아닌 값 타입을 컬렉션에 쓰는 것.

     

    값 타입❓ 엔티티 ❓

    값 타입은 흔히 엔티티와 많이 비교 된다.

    엔티티는 흔히 @Entity로 정의하는 객체이며 @Id라는 어노테이션으로 정의한 PK(식별자)를 통해 계속적으로 추적이 가능하다.

    하지만, 값 타입은 식별자라는 개념이 존재하지 않아 추적이 어렵다.

    • 값 타입은 흔히 우리가 사용하는 Integer, String 과 같은 자바 원시타입과 같은 존재이다.
    • 흔히 사용하는 객체와 달리 공유에 안전하고 side effect가 발생하지 않는다.

    임베디드 타입의 경우에는 구성 요소 자체가 값 타입으로 이루어져 있긴 하지만 임베디드 타입 자체가 불변 객체가 아니기 때문에 위의 장점을 포함하진 않는다.

     

    값 타입 컬렉션

    • 값 타입을 저장하는 것!! ( 값 타입을 하나 이상 저장할 때 사용 )
    • 변경사항이 생기면 모두를 지웠다가 다시 만든다.
    public class Member {
        @Id
        private Long id;
        
        private Set<String> favoriteFoods;
        private List<Address> addressHistory;
    }

    RDB에는 내부적으로 컬렉션을 담을 수 있는 구조가 없다

    • 그저 값만 넣을 수 있는 구조이다.
    • 컬렉션은 1 : N의 개념이기 때문에 DB는 컬렉션을 하나의 테이블에 저장할 수 없다.
    • 이런 관계를 DB 테이블에 저장하려면 별도의 테이블이 필요하다

    예시

    @Entity
    public class Member {
        ...
    
        @ElementCollection
        @CollectionTable(
            name = "FAVORITE_FOOD",
            joinColumns = @JoinColumn(name = "MEMBER_ID"))
        @Column(name = "FOOD_NAME") // 컬럼명 지정 (예외)
        private Set<String> favoriteFoods = new HashSet<>();
    
        @ElementCollection
        @CollectionTable(
            name = "ADDRESS",
            joinColumns = @JoinColumn(name = "MEMBER_ID"))
        private List<Address> addressHistory = new ArrayList<>();
    
        ...
    }
    • @ElementCollection
      • 값 타입 컬렉션을 구현할 수 있도록 해주는 어노테이션
    • @CollectionTable
      • 테이블의 이름은 어떤 것으로 할 것이고
      • 조인할 때 사용할 컬럼을 지정
    • @Column
      • 실제 저장되는 컬럼을 설정

    특징

    • 값 타입이기 때문에 별도의 생명주기가 없고 엔티티의 라이프 사이클에 의존한다.
      • 값 타입은 별도로 persist 또는 update를 할 필요가 없이 entity에서 값을 변경하면 자동으로 처리해줌
      • 1:N 연관관계에서 Cascade = ALL로 설정하고, orphanRemoval=true로 설정한 것과 유사하다.
    • 값 타입 컬렉션은 영속성 전이(Cascade) + 고아 객체 제거 기능을 필수로 가진다고 볼 수 있다.

     

    • @ElementCollection 어노테이션의 fetch 기본값은 LAZY이다.
      • 컬렉션 값 타입들은 지연 로딩
      • ←→ Embedded 타입의 속성들은 같이 조회 된다.
    • 값 타입 컬렉션에 변경사항이 생기면 주인 엔티티와 연관된 모든 데이터를 삭제 후, 값 타입 컬렉션에 있는 현재 값을 모두 다시 저장
    • 값 타입 컬렉션을 매핑하는 테이블은 모든 컬럼을 묶어서 기본키를 구성해야 한다.
      • null ❌
      • 중복 저장 ❌

     

    값 타입 컬렉션 대안

    실무에서는 상황에 따라 값 타입 컬렉션 대신 1:N 관계를 고려한다.

    • 일대다 관계를 위한 엔티티를 만들고, 여기에서 값 타입을 사용
    • 영속성 전이(Cascade) + 고아객체제거를 사용해 값 타입 컬렉션처럼 사용한다.
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "MEMBER_ID")
    private List<AddressEntity> addressHistory = new ArrayList<AddressEntity>();
    @Entity
    public class AddressEntity {
    
      @Id
      @GeneratedValue
      private Long id;
        
      @Embedded 
      Address address;
        
      ...
    }

    @ElementCollection vs 연관관계(OneToMany, ManyToOne)


    @ElementCollection

    • 부모 entity에 의해 관리가 된다.
    • 부모와 함께 저장되고 삭제된다.
    • 컬렉션 값 변경시 → 전체 삭제, 새로 추가

    연관관계

    • 여러 Entity와 연관관계를 맺을 수 있다.
    • 연관관계를 맺을 때 보통 ID만으로 연관을 맺는다.

     

    참고 자료

    https://gilssang97.tistory.com/74

    https://insanelysimple.tistory.com/350

    https://gmlwjd9405.github.io/2019/09/13/value-type-of-collection-copy.html

    '🌱 spring' 카테고리의 다른 글

    Spring Interceptor에서 Request 데이터 처리  (1) 2022.12.06
    애플리케이션 컨텍스트와 빈팩토리  (0) 2022.11.16
    JPA - Embedded Type  (0) 2022.11.02
    Spring Scheduler  (0) 2022.10.24
    Filter, Interceptor  (0) 2022.10.11

    댓글

Designed by Tistory.