JPA에서는 값 타입을 크게 세 가지로 구분함.
(1) 기본 값 타입
• int, String, Integer, Long 같은 기본형(primitive type)과 래퍼(wrapper) 타입
• 별도의 매핑 없이 바로 사용 가능
@Entity
public class User {
@Id @GeneratedValue
private Long id;
private String name; // 기본 값 타입
private int age; // 기본 값 타입
}
(2) 임베디드 값 타입 (@Embeddable)
사용 방법:
1. @Embeddable : 값 타입을 정의
2. @Embedded : 엔티티에서 값 타입을 포함
@Embeddable
public class Address {
private String city;
private String street;
private String zipcode;
protected Address() {} // JPA 기본 생성자 필요
public Address(String city, String street, String zipcode) {
this.city = city;
this.street = street;
this.zipcode = zipcode;
}
}
@Entity
public class User {
@Id @GeneratedValue
private Long id;
private String name;
@Embedded // Address 값 타입 포함
private Address address;
protected User() {}
public User(String name, Address address) {
this.name = name;
this.address = address;
}
}
(3) 값 타입 컬렉션 (@ElementCollection)
• 컬렉션(List, Set, Map) 형태로 값 타입을 저장
• 별도의 테이블을 만들어 저장하며, 연관관계를 가지지 않음
• @ElementCollection과 @CollectionTable을 사용
예제: 사용자의 여러 개의 주소 저장
@Embeddable
public class Address {
private String city;
private String street;
private String zipcode;
protected Address() {}
public Address(String city, String street, String zipcode) {
this.city = city;
this.street = street;
this.zipcode = zipcode;
}
}
@Entity
public class User {
@Id @GeneratedValue
private Long id;
private String name;
@ElementCollection // 값 타입 컬렉션
@CollectionTable(name = "user_address", joinColumns = @JoinColumn(name = "user_id"))
private List<Address> addresses = new ArrayList<>();
public void addAddress(Address address) {
addresses.add(address);
}
}
단점
1. 값 타입은 불변 객체로 설계하는 것이 좋음
📌 불변 객체로 설계하는 방법
@Embeddable
public class Address {
private final String city;
private final String street;
private final String zipcode;
protected Address() {} // JPA 기본 생성자
public Address(String city, String street, String zipcode) {
this.city = city;
this.street = street;
this.zipcode = zipcode;
}
// 값 변경 시 새로운 객체 생성
public Address changeCity(String newCity) {
return new Address(newCity, this.street, this.zipcode);
}
}
user.setAddress(user.getAddress().changeCity("부산")); // 새로운 객체 할당
✔ 값 타입은 엔티티가 아닌 “엔티티 내부의 데이터 묶음”
✔ 엔티티는 식별자가 있지만, 값 타입은 식별자가 없음
✔ 임베디드 타입(@Embeddable)을 사용하면 객체지향적인 설계가 가능
✔ 값 타입은 불변 객체로 설계하는 것이 안전
✔ 값 타입 컬렉션(@ElementCollection)은 편리하지만 대량 변경 시 비효율적일 수 있음