본문 바로가기

JPA/값 타입

값 타입 컬렉션을 엔티티로 승격시키기

2021.09.04 - [JPA/값 타입] - 값 타입 컬렉션

 

값 타입 컬렉션

우리가 지금까지 배운 값 타입을 컬렉션으로 사용할 수도 있다. 하지만 명확한 단점때문에 사용하는 상황이 한정돼있다. 이번 글에서는 값 타입 컬렉션에 대해서 알아보자! github 전체코드 주소(

code-mania.tistory.com

 

2021.08.24 - [JPA] - 영속성 전이(CASCADE)와 고아객체

 

영속성 전이(CASCADE)와 고아객체

영속성 전이란? Shop-Item이라는 엔티티가 관계를 맺고 있다고 해보자! 일반적으로 Item은 Shop이 없다면 Item 자체만으로는 의미를 가지지 못한다. 이런 경우 Shop을 제거하면 Item도 제거되어야 한다.

code-mania.tistory.com


값 타입 컬렉션을 사용하기 부적절한 경우 값 타입 컬렉션을 엔티티로 승격시켜야 한다고 했다.
사실 엔티티로 승격시킨다는 말이 엄청 거창하지만, 그냥 엔티티를 만들면 끝이다.
엔티티만 만드는 것은 너무 쉬우니 엔티티를 값 타입 컬렉션처럼 다루는 법을 알아보겠다.
(이 때 영속성전이[cascade]와 고아객체 제거 기능을 사용하니 관련 지식에 대해 궁금하다면 위의 글을 읽어보자!)

github 전체코드 주소(branch: valueTypeToEntity)


값 타입 컬렉션을 엔티티로 승격시키기

AddressEntity.java

package hellojpa;

import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Data
@Entity
@NoArgsConstructor
public class AddressEntity {
    @Id @GeneratedValue
    Long id;

    @Embedded
    Address address;

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

 

Student.java

package hellojpa;

import lombok.Data;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Entity
@Data
public class Student {

    @Id
    @GeneratedValue
    private Long id;

    private String name;

    private int age;

    @ElementCollection
    @CollectionTable(name = "FAVORITE_SUBJECT"
            , joinColumns = @JoinColumn(name = "MEMBER_ID"))
    @Column(name = "SUBJECT_NAME")
    private Set<String> favoriteSubjects = new HashSet<>();

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

엔티티를 값 타입 컬렉션처럼 다룬다는 것은 Student가 AddressEntity를 소유하고 관리한다는 뜻이다.
즉, AddressEntity의 라이프사이클이 Student에 종속되고,
AddressEntity에서 FK 값을 관리하지 않고, Studen에서 관리한다.
(물론 위 방법 말고, AddressEntity에서 FK를 관리하는 것도 아주 좋은 방법이다.)

라이프사이클 관리를 위해 cascade 옵션을 지정하였고,
List에서 요소 제거 시 DB에서도 제거시키기 위해 orphanRemoval 옵션을 지정하였다.
(앞선 글들에서 살펴봤던 내용이기에 더 이상의 자세한 설명은 생략합니다 ㅠㅠㅠ)

 

JpaMain.java - 값 수정하기

// 수정 코드
favoriteSubjects.remove("역사");
favoriteSubjects.add("과학");

Address address = new Address("서울특별시", "세종대로", "10000");
findStudent.getAddressHistory().get(0).setAddress(new Address(address.getCity(), address.getStreet(), "65202"));

값 타입 컬렉션을 엔티티로 승격한 후와 승격 전을 비교해보면 장점을 체감할 수 있다.
승격 전에는 remove 후 add를 했지만, 승격 후에는 setter를 통해 수정 가능하다.
(수정하고싶은 데이터가 List에서 몇 번째 index인지 모른다면 for와 if문을 통해 찾아내면 된다)

 

실행 후 log

AddressEntity가 Entity이기 때문에 식별자(PK)를 통해 값이 update되는 것을 볼 수 있다.

기존의 값 타입 컬렉션이 Entity로 승격되었기때문에
수정할 때뿐만이 아니라 다른 부분에서도 Entity의 이점을 누릴 수 있다.

 

참고강의: 배달의 민족 개발팀장 김영한 강사님의 JPA 강의

'JPA > 값 타입' 카테고리의 다른 글

값 타입 컬렉션  (0) 2021.09.04
값 타입의 비교  (0) 2021.08.31
임베디드 타입과 불변 객체  (0) 2021.08.28
임베디드 타입  (0) 2021.08.28
값 타입  (0) 2021.08.28