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문을 통해 찾아내면 된다)
AddressEntity가 Entity이기 때문에 식별자(PK)를 통해 값이 update되는 것을 볼 수 있다.
기존의 값 타입 컬렉션이 Entity로 승격되었기때문에
수정할 때뿐만이 아니라 다른 부분에서도 Entity의 이점을 누릴 수 있다.