값 타입을 하나 이상 저장하려면 컬렉션에 보관하고 아래 두 개의 어노테이션을 사용하면 된다.
@ElementCollection
@CollectionTable
✅ Member
package jpabook.model.entity;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
@Embedded
private Address homeAddress;
@ElementCollection
@CollectionTable(name = "FAVORITE_FOODS", joinColumns = @JoinColumn(name="MEMBER_ID"))
@Column(name = "FOOD_NAME")
private Set<String> favoriteFoods = new HashSet<String>();
@ElementCollection
@CollectionTable(name = "FAVORITE_FOODS", joinColumns = @JoinColumn(name="MEMBER_ID"))
@Column(name = "FOOD_NAME")
private List<Address> addressHistory = new ArrayList<Address>();
}
✅ Address
package jpabook.model.entity;
import javax.persistence.Column;
import javax.persistence.Embeddable;
@Embeddable
public class Address {
@Column
private String city;
private String street;
private String zipcide;
}
✅ 값 타입 UML
✅ 값 타입 컬렉션 ERD
Member 엔티티를 보면 값 타입 컬렉션을 사용하는
favoriteFoods , addressHistory 에다가 @ElementCollection 지정했다.
favoriteFoods 는 기본값 타입인 String 을 컬렉션으로 가진다.
이것을 DB Table 로 매핑해야 하는데
관계형 데이터베이스 테이블은 컬럼 안에 컬렉션을 포함할 수 없다.
따라서 아래처럼 별도의 테이블을 추가하고 @CollectionTable 을 사용해서 추가한 테이블을 매핑해야 한다.
그리고 favoriteFoods 처럼 값으로 사용되는 컬럼이 하나면 @Column 울 사용해서 컬럼명을 지정할 수 있다.
addressHistory 는 임베디드 타입인 Address 를 컬렉션으로 가진다.
이것도 마찬가지로 별도의 테이블을 사용해야 한다.
그리고 테이블 매핑 정보는 @AttribyteOverride 를 사용해서 재정의 할 수 있다.
@CollectionTable 을 생략하면 기본 값을 사용해소 매핑한다.
기본값 : {엔티티이름}_{컬렉션 속성}
예를 들어 Member 엔티티의 addressHistory는 Member_addressHistory 테이블과 매핑한다.
✅ 값 타입 컬렉션 등록
Member member = new Member();
// 임베디드 값 타입
member.setHomeAddress( new Address("통영", "몽골", "123-123") );
// 기본값 타입 컬렉션
member.getFavoriteFoods().add("짬뽕");
member.getFavoriteFoods().add("짜장");
member.getFavoriteFoods().add("울면");
// 임베디드 값 탕비 컬렉션
member.getAddressHistory().add( new Address("서울", "강서", "123-990") );
member.getAddressHistory().add( new Address("서울", "강북", "321-777") );
em.persist(member)
등록하는 코드만 보면 마지막에 member 엔티티만 영속화 했다.
JPA 는 이때 MEMBER 엔티티 값 타입도 함께 저장한다.
실제 DB 에 실행되는 INSERT SQL 은 아래와 같다.
- member
- INSERT 1 번
- member.homeAddress
- 컬렉션이 아닌 임베디드 값 타입이므로 회원 테이블을 저장하는 SQL 에 포함된다.
- member.favoriteFoods
- INSERT SQL 3번
- member.addressHitory
- INSERT SQL 2번
따라서 em.persist(member) 한 번의 호출로 총 6 번의 INSERT SQL 이 실행된다.
INSERT INTO MEMBER VALUES ( 1, "통영", "몽골", "123-123" )
INSERT INTO FAVORITE_FOODS VALUES ( 1 , "짬뽕" )
INSERT INTO FAVORITE_FOODS VALUES ( 1 , "짜장" )
INSERT INTO FAVORITE_FOODS VALUES ( 1 , "울면" )
INSERT INTO ADDRESS VALUES ( 1 , "서울", "강서", "123-990" )
INSERT INTO ADDRESS VALUES ( 1 , 서울", "강북", "321-777" )
'개발중 > Java Persistence API (JPA)' 카테고리의 다른 글
객체 지향 쿼리 소개 (0) | 2021.07.01 |
---|---|
Java 객체/ 기본값 타입의 특징 (0) | 2021.06.30 |
JPA - 즉시 로딩과 지연 로딩 (0) | 2021.06.28 |
JPA / 프록시 알아보기 (0) | 2021.06.28 |
식별 관계와 비식별 관계 구분 (0) | 2021.06.25 |