[JPA BASIC] 4. Type
in Jpa on Jpa
값타입
값 타입은 식별자 없이 엔티티에 종속되어 값으로만 사용되는 객체이며, @Id가 붙는 식별자는 값 타입이 아니다. 엔티티에 값이 될 수 있는 것들을 알아보자!
- 값 타입
종류
- 기본값 타입
- 임베디드 타입
- 컬렉션 타입
기본 값 타입 (Primitive Type)
- 자바의 기본 타입 int, double, boolean 등과 그에 대응하는 래퍼 클래스, String, Date 등
- 특별한 매핑 없이 JPA가 자동으로 처리
- 불변성 유지가 어렵고, 여러 엔티티에서 공유 시 문제가 생길 수 있음
int age; // 자바 기본 타입(primitive type)
Integer count; // Wrapper 클래스
String name;
여러 엔티티 공유 예시(문제가 생길 수 있음)
String address = "Seoul";
member1.setAddress(address);
member2.setAddress(address);
address = "Busan"; // 외부에서 값을 변경
임베디드 타입
- 기본 값 타입을 모아서 복합 값 타입을 만든다.
복합 키(Composite Key)
를 하나의 임베디드 타입으로 정의하여, 엔티티의 식별자로 사용할 수 있다.@Embeddable
: 값 타입을 정의하는 곳에 표시@Embedded
: 값 타입을 사용하는 곳에 표시- 기본 생성자 필수
- 임베디드 타입을 포함한 모든 값 타입은, 값 타입을 소유한 엔티티에 생명주기를 의존함
- 임베디드 타입의 값이 null이면 매핑한 컬럼 값은 모두 null
- 여러 엔티티에서 공유하면 위험함
@Embeddable
클래스가@EmbeddedId(복합 키)
로 사용될 경우equals()
와hashCode()
메소드를 반드시재정의(override)
해야 한다.(동등성 보장)
// 임베디드 타입
@Embeddable
@Getter
@EqualsAndHashCode
public class Address {
private String city;
private String street;
private String zipcode;
}
}
// 엔티티
@Entity
@Getter @Setter
public class Member {
@Id
@GeneratedValue
@Column(name = "member_id")
private Long id;
private String name;
@Embedded
private Address address;
}
@EmbeddedId(복합 키)
Serializable
를 써줄것equals()
와hashCode()
메소드를 반드시 재정의(롬복 사용 가능)
// 복합키 임베디드 타입
@Embeddable
@NoArgsConstructor
public class TaskId implements Serializable {
@Column(name = "employee_id", length = 50)
private String employeeId;
@Column(name = "task_id", length = 11)
private int taskId;
public TaskId(String employeeId, int taskId) {
this.employeeId = employeeId;
this.taskId = taskId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TaskId taskId1 = (TaskId) o;
return taskId == taskId1.taskId && Objects.equals(employeeId, taskId1.employeeId);
}
@Override
public int hashCode() {
return Objects.hash(employeeId, taskId);
}
}
// 엔티티
@Setter
@Entity
@NoArgsConstructor
public class Task {
@EmbeddedId
private TaskId taskId;
@Column(name = "task_name", length = 100)
private String taskName;
@Column(name = "date")
@UpdateTimestamp
private LocalDateTime updatedDate;
}
@AttributeOverride: 속성 재정의
- 한 엔티티에서 같은 값 타입을 사용하면?
- 컬럼 명이 중복됨
- @AttributeOverrides, @AttributeOverride를 사용해서 컬럼 명 속성을 재정의
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "city", column = @Column(name = "home_city")),
@AttributeOverride(name = "street", column = @Column(name = "home_street")),
@AttributeOverride(name = "zipcode", column = @Column(name = "home_zipcode"))
})
private Address homeAddress;
불변 객체
- 객체 타입을 수정할 수 없게 만들면 부작용을 원천 차단
- 값 타입은 불변 객체(immutable object)로 설계해야함
- 불변 객체: 생성 시점 이후 절대 값을 변경할 수 없는 객체
- 생성자로만 값을 설정하고
수정자(Setter)
를 만들지 않으면 됨 - 참고:
Integer
,String
은 자바가 제공하는 대표적인 불변 객체
컬렉션 타입
- 값 타입을 하나 이상 저장할 때 사용
- @ElementCollection, @CollectionTable 사용
- 데이터베이스는 컬렉션을 같은 테이블에 저장할 수 없다.
- 컬렉션을 저장하기 위한 별도의 테이블이 필요함
- 값 타입 컬렉션은 영속성 전에(Cascade) + 고아 객체 제거 기능을 필수로 가진다.
- 개인적인 생각으론 컬렉션을 쓸 일이 있는지 모르겠다. 되도록 일대다 관계를 고려 하자.