- 값 타입을 하나 이상 저장할 때 사용
- @ElementCollection, @CollectionTable 사용
- 데이터베이스는 컬렉션을 같은 테이블에 저장 할 수 없다.
- 컬렉션을 저장하기 위한 별도의 테이블이 필요
Member member = new Member();
member.setUsername("member1");
member.setHomeAddress(new Address("homeCity","Street", "10000"));
member.getFavoriteFoods().add("족발");
member.getFavoriteFoods().add("치킨");
member.getFavoriteFoods().add("피자");
member.getAddressHistory().add(new Address("old1","street", "10000"));
member.getAddressHistory().add(new Address("old2","street", "10000"));
em.persist(member);
em.flush();
em.clear();
System.out.println("============ START ===================");
Member findMember = em.find(Member.class, member.getId());
// 값 타입은 데이터 수정 시 아예 새로 넣어야한다. 변경하려는 값만 변경 하면 X(통째로 갈아끼워야함 update X )
// 만약 주소를 homeCity -> newCity로 바꾸려면?
/* 잘못된 예제 */
// findMember.getHomeAddress().setCity("newCity");
/* 좋은 예제 */
Address a = findMember.getHomeAddress();
findMember.setHomeAddress(new Address("newCity", a.getStreet(), a.getZipcode()));
// 만약 치킨 -> 한식 바꾸려면? : 값타입은 지우고 다시 추가해줘야함
findMember.getFavoriteFoods().remove("족발");
findMember.getFavoriteFoods().add("떡볶이");
// remove은 기본적으로 equals를 사용학기 때문에 비교값을 완전 똑같이 넣어줘야 한다.
findMember.getAddressHistory().remove(new Address("old1","street", "10000"));
findMember.getAddressHistory().add(new Address("newCity1","street", "10000"));
값 타입 컬렉션 사용
- 값 타입 컬렉션도 지연 로딩 전략을 사용한다.
- 값 타입 컬렉션은 영속성 전에(Cascade) + 고아 객체 제거 기능을 필수도 가진다고 볼 수 있다.
제약사항
- 값 타입은 엔티티와 다르게 식별자 개념이 없다 → 따라서 값을 변경하면 추적이 어렵다.
- 값 타입 컬렉션에서 변경사항이 생기면, 주인 엔티티와 관련 있는 모든 데이터를 삭제하고 다시 저장한다.
- 값 타입 컬렉션을 매핑하는 테이블은 모든 컬럼을 묶어서 기본키를 구성해야 함
- null 입력 X, 중복 X → 값 타입은 pk가 없고 딱히 pk로 지정해줘야하는 값도 없기 때문에 전체를 기본키로 구성한다.
값 타입 컬렉션 대안
- 실무에서는 값 타입 컬렉션 대신에 일대다 관계를 고려
- 일대다 관계를 위한 엔티티를 만들고, 여기에서 값 타입을 사용
- 영속성 전이(Cascade) + 고아 객체 제거 를 사용해서 값 타입 컬렉션 처럼 사용
ex ) AddressEntity.java
@Entity
@Getter
@Table(name = "address")
public class AddressEntity {
@Id @GeneratedValue
private Long id;
private Address address;
public AddressEntity() {
}
public AddressEntity(String city, String street, String zipcode) {
this.address = new Address(city, street, zipcode);
}
}
Member.java
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) //cascate, 고아객체제거
@JoinColumn(name = "MEMBER_ID")
private List<AddressEntity> addressHistory = new ArrayList<>();
★ 정리
- 값 타입은 정말 값 타입이라고 판단될 때만 사용
- 엔티티와 값 타입을 혼동해서 엔티티를 값 타입으로 만들면 안됨
- 식별자가 필요하고, 지속해서 값을 추적, 변경 해야 한다면 그것은 엔티티
'JAVA' 카테고리의 다른 글
[JAVA] JPA 조인과 서브쿼리 (0) | 2022.01.18 |
---|---|
[JAVA] 프로젝션과 페이징 (0) | 2022.01.13 |
[JAVA] 값 타입과 불변객체 (0) | 2022.01.11 |
[JAVA] 임베디드 타입(복합값) (0) | 2022.01.11 |
[JAVA] 영속성 전이(CASCADE) + 고아객체 (0) | 2022.01.06 |