JPA

[JPA] 19. 값 타입 컬렉션

inuma 2021. 1. 23. 00:58
프로젝트 git url github.com/rtef23/JpaStudy
필요 1. docker
2. docker-compose
프로젝트 정보 mysql : 5.7 - docker image
java : 1.8

 

값 타입 컬렉션

  • 값 타입을 하나 이상 저장할 때 사용
  • @ElementCollection, @CollectionTable 사용
  • 데이터베이스는 컬렉션을 같은 테이블에 저장할 수 없다.
    • 컬렉션을 저장하기 위한 별도의 테이블이 필요함
  • 값 타입 컬렉션도 기본으로는 지연 로딩 전략 사용
  • 값 타입 컬렉션의 경우, 영속성 전이(CASCADE) + 고아 객체 제거 기능을 필수로 가지게 된다.

@Entity
public class Member {
  @Id
  @GeneratedValue
  @Column(name = "member_id")
  private Long id;

  private String name;

  @ElementCollection
  @CollectionTable(name = "FAVORITE_FOOD", joinColumns = @JoinColumn(name = "member_id"))
  @Column(name = "food_name")//@CollectionTable과 함께 사용하는 경우 예외케이스로서, 저장되는 테이블에서 컬럼명은 food_name으로 사용한다는 표시
  private Set<String> favoriteFoods = new HashSet<>();

  @ElementCollection
  @CollectionTable(name = "ADDRESS", joinColumns = @JoinColumn(name = "member_id"))
  private List<Address> addressHistory = new ArrayList<>();
  
  ...
}

@Embeddable
public class Address {
  private String city;
  private String street;
  private String zipcode;
  
  ...
}
Member member = new Member();

Set<String> favoriteFoods = new HashSet<>();
favoriteFoods.add("food-1");
favoriteFoods.add("food-2");

member.setName("name-1");
member.setFavoriteFoods(favoriteFoods);
member.setAddressHistory(
    Arrays.asList(
       new Address("city1", "street1", "zipcode1"),
       new Address("city2", "street2", "zipcode2"),
       new Address("city3", "street3", "zipcode3")));

entityManager.persist(member);

 

값 타입 제약사항

  • 값 타입은 엔티티와 다르게 식별자 개념이 없다.

  • 값은 변경하면 추적이 어렵다.
  • 값 타입 컬렉션에 변경 사항이 발생하면, 주인 엔티티와 연관된 모든 데이터를 삭제하고, 값 타입 컬렉션에 있는 현재 값을 모두 다시 저장한다.(연관된 데이터 full delete && re-insert)
  • 값 타입 컬렉션을 매핑하는 테이블은 모든 컬럼을 묶어서 기본키를 구성해야 한다.(not null, unique)

 

값 타입 컬렉션 대안

  • 상황에 따라 값 타입 컬렉션 대신에 일대다 관계를 고려
  • 일대다 관계를 위한 엔티티를 만들고, 여기서 값 타입을 사용
  • 영속성 전이(CASCADE) + 고아 객체 제거를 사용해서 값 타입 컬렉션처럼 사용하도록 한다.
@Entity
public class Member {
  @Id
  @GeneratedValue
  @Column(name = "member_id")
  private Long id;

  private String name;

  @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
  @JoinColumn(name = "member_id")
  private List<AddressEntity> addressHistory = new ArrayList<>();
  
  ...
}

@Entity
public class AddressEntity {
  @Id
  @GeneratedValue
  @Column(name = "address_id")
  private Long id;

  private Address address;
  
  public AddressEntity(String city, String street, String zipcode) {
    this.address = new Address(city, street, zipcode);
  }
  
  ...
}

 

엔티티 VS 값 타입 특징

엔티티 타입의 특징

  • 식별자 존재
  • 생명 주기 관리
  • 공유 가능

값 타입의 특징

  • 식별자 존재하지 않음
  • 생명 주기를 엔티티에 의존
  • 공유하지 않는 것이 안전(불변 객체로만 사용)

 

'JPA' 카테고리의 다른 글

[JPA] 21. JPQL - 기본 문법 1  (0) 2021.01.26
[JPA] 20. JPA 쿼리 방법 소개  (0) 2021.01.25
[JPA] 18. 값 타입 - 불변 객체  (0) 2021.01.21
[JPA] 17. 값 타입  (0) 2021.01.21
[JPA] 16. 영속성 전이(CASCADE)  (0) 2021.01.18