값 타입은 3가지로 나눌 수 있다.
- 기본값 타입(자바 기본 타입, 래퍼 클래스, String)
- 임베디드 타입
- 컬렉션 값 타입
1. 기본값 타입
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String name;
private int age;
...
}
Member 엔티티에서 String, int가 값 타입이다. Member 엔티티는 id라는 식별자 값도 가지고 생명주기도 있지만 값 타입인 name, age 속성은 식별자 값도 없고 생명주기도 회원 엔티티에 의존한다. 따라서 회원 엔티티 인스턴스를 제거하면 name, age 값도 제거된다. 그리고 값 타입은 공유하면 안된다.
2. 임베디드 타입(복합 값 타입)
새로운 값 타입을 직접 정의해서 사용한다. 중요한 것은 직접 정의한 임베디드 타입도 int, String 처럼 값 타입이라는 것이다.
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String name;
//근무 기간
@Temporal(TemporalType.DATE) java.util.Date startDate;
@Temporal(TemporalType.DATE) java.util.Date endDate;
//주소
private String city;
private String street;
private String zipcode;
...
}
회원이 상세한 데이터를 가지고 있는것은 객체지향적이지 않으며 응집력만 떨어뜨린다. 대신에 근무 기간, 주소 같은 타입이 있다면 코드가 더 명확해질 것이다.
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String name;
@Embedded Period workPeroid; //근무 기간
@Embedded Address home Address; //주소
...
}
//근무 기간 임베디드 타입
@Embeddable
public class Period {
@Temporal(TemporalType.DATE) java.util.Date startDate;
@Temporal(TemporalType.DATE) java.util.Date endDate;
...
public boolean isWork(Date date) {
// 값 타입을 위한 메소드를 정의할 수 있다.
}
}
//주소 임베디드 타입
@Embeddable
public class Address {
@Column(name="city") //매핑할 컬럼 지정 가능
private String city;
private String street;
private String zipcode;
...
}
임베디드 타입은 기본 생성자가 필수다. 임베디드 타입을 포함한 모든 값 타입은 엔티티의 생명주기에 의존하므로 엔티티와 임베디드 타입의 관계를 UML로 표현하면 컴포지션 관계가 된다.
임베디드 타입과 테이블 매핑
임베디드 타입을 쓰건 안쓰건 테이블에 매핑하는건 같다. 잘 설계한 ORM 애플리케이션은 매핑한 테이블의 수보다 클래스의 수가 더 많다.
@AttributeOverride: 속성 재정의
임베디드 타입에 정의한 매핑정보를 재정의하려면 엔티티에 @AttributeOverride를 사용하면 된다. 예를들어 회원에게 주소가 하나 더 필요하다면?
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String name;
@Embedded Address homeAddress;
@Embedded Address companyAddress;
}
위의 코드를 보면 집 주소에 회사 주소를 하나 더 추가했다. 문제는 테이블에 매핑하는 컬럼명이 중복되는 것이다. 이때는 @AttributeOverrides를 사용해서 매핑정보를 재정의해야 한다.
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String name;
@Embedded Address homeAddress;
@Embedded
@AttributeOverrides({
@AttributeOverride(name="city", column=@Column(name="COMPANY_CITY")),
@AttributeOverride(name="street", column(@Column(name="COMPANY_STREET")),
@AttributeOverride(name="zipcode", column(@Column(name="COMPANY_ZIPCODE"))
})
Address companyAddress;
}
CREATE MEMBER (
COMPANY_CITY varchar(255),
COMPANY_STREET varchar(255),
COMPANY_ZIPCODE varchar(255),
city varchar(255),
street varchar(255),
zipcode varchar(255),
...
}
| id | name | city | street | zipcode | COMPANY_CITY | COMPANY_STREET | COMPANY_ZIPCODE |
|----|-------|--------------|----------------|---------------|----------------|----------------|-----------------|
| 1 | John | Home City | Home Street | Home Zipcode | Company City | Company Street | Company Zipcode |
@AttributeOverride를 사용하면 어노테이션을 너무 많이 사용해서 엔티티 코드가 지저분해진다. 한 엔티티에 같은 임베디드 타입을 중복해서 사용하는 일은 많지 않다.
'JPA' 카테고리의 다른 글
JPQL - (기본 문법, 쿼리 API, 페이징 API, 집합과 정렬) (0) | 2023.09.25 |
---|---|
객체지향 쿼리 언어 소개 (0) | 2023.09.22 |
영속성 전이: CASCADE (0) | 2023.07.31 |
즉시 로딩과 지연 로딩 (0) | 2023.07.31 |
프록시 (0) | 2023.07.28 |