값 타입 컬렉션
- 값 타입을 하나 이상 저장할 때 사용
- @ElementCollection, @CollectionTable
주요 특징
- 데이터베이스는 컬렉션을 같은 테이블에 저장 불가 -> 별도의 테이블이 필요
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String userName;
@Embedded
private Address homeAddress;
// 값 타입 컬렉션 사용
@ElementCollection
// FAVORITE_FOOD 테이블 정의
@CollectionTable(name = "FAVORITE_FOOD", joinColumns =
@JoinColumn(name = "MEMBER_ID"))
@Column(name = "FOOD_NAME")
private Set<String> favoriteFoods = new HashSet<>();
// 값 타입 컬렉션 사용
@ElementCollection
// ADDRESS 테이블 정의
@CollectionTable(name = "ADDRESS", joinColumns =
@JoinColumn(name = "MEMBER_ID"))
private List<Address> addressHistory = new ArrayList<>();
...
}
- 값 타입 컬렉션은 지연로딩
public static void main(String[] args) {
...
try{
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();
Member findMember = em.find(Member.class, member.getId());
// 지연 로딩
List<Address> addressHistory = findMember.getAddressHistory();
for (Address address : addressHistory) {
System.out.println("address = " + address.getCity());
}
Set<String> favoriteFoods = findMember.getFavoriteFoods();
for (String favoriteFood : favoriteFoods) {
System.out.println("favoriteFood = " + favoriteFood);
}
tx.commit();
} catch(Exception e) {
tx.rollback();
} finally {
em.close();
}
emf.close();
}
제약 사항
- 값 타입은 엔티티와 다르게 식별자 개념이 없음
- 값 타입 컬렉션에 변경 사항이 발생하면 주인 엔티티와 연관된 모든 데이터를 삭제하고 값 타입 컬렉션에 있는 현재 값을 모두 다시 저장
- 즉, 값은 변경하면 추적이 어려움
public static void main(String[] args) {
...
try{
Member member = new Member();
member.setUserName("member1");
member.setHomeAddress(new Address("homeCity","STREET","10000"));
member.getAddressHistory().add(new Address("old1","STREET","10000"));
member.getAddressHistory().add(new Address("old2","STREET","10000"));
em.persist(member);
em.flush();
em.clear();
findMember.getAddressHistory().remove(new Address("old1","STREET","10000"));
findMember.getAddressHistory().add(new Address("new1","STREET","10000"));
tx.commit();
} catch(Exception e) {
tx.rollback();
} finally {
em.close();
}
emf.close();
}
- DELETE : 모든 데이터 삭제
- 첫번째 INSERT : 기존 데이터(old2) 삽입
- 첫번째 INSERT : 신규 데이터(new2) 삽입