01. 임베디드 타입
임베디드 타입
새로운 값 타입을 직접 정의할 수 있다.
주로 기본 값 타입을 모아서 만들어 복합 값 타입이라고도 한다.
회원 엔티티
회원 엔티티는 다음과 같이 이름, 근무 시작일, 근무 종료일, 도시, 번지, 우편번호를 가진다.
근무 시작일, 근무 종료일이 비슷한 속성이고, 도시, 번지, 우편번호가 비슷한 속성이므로 회원 엔티티는 다음과 같이 이름, 근무 기간, 집 주소를 가질 수 있다.
02. 임베디드 타입 사용법
임베디드 타입 사용법
값 타입을 정의하는 곳에 @Embeddable
를 작성한다. 값 타입을 사용하는 곳에 @Embedded
를 작성한다.
기본 생성자는 필수로 있어야 한다.
예시 코드
Member 클래스가 다음과 같이 정의되었을 때, startDate와 endDate를 Period로 묶고 city, street, zipcode는 Address로 묶고싶다고 가정한다.
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER\_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "TEAM\_ID")
private Team team;
private LocalDateTime startDate;
private LocalDateTime endDate;
private String city;
private String street;
private String zipcode;
}
위 코드를, 다음과 같이 바꾼다. 묶을 속성들을 하나의 클래스로 묶고, @Embeddable
을 작성한다. 해당 클래스들에는 기본 생성자가 반드시 있어야 한다. 조회 등의 작업을 하기 위해 getter와 setter를 선언한다.
package hellojpa;
import javax.persistence.Embeddable;
import java.time.LocalDateTime;
@Embeddable
public class Period {
private LocalDateTime startDate;
private LocalDateTime endDate;
public Period() {
}
public LocalDateTime getStartDate() {
return startDate;
}
public void setStartDate(LocalDateTime startDate) {
this.startDate = startDate;
}
public LocalDateTime getEndDate() {
return endDate;
}
public void setEndDate(LocalDateTime endDate) {
this.endDate = endDate;
}
}
package hellojpa;
import javax.persistence.Embeddable;
@Embeddable
public class Address {
private String city;
private String street;
private String zipcode;
public Address() {
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getZipcode() {
return zipcode;
}
public void setZipcode(String zipcode) {
this.zipcode = zipcode;
}
}
기존에 있는 클래스에는 묶은 클래스를 선언하고 @Embedded
를 작성하면 된다.
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "TEAM_ID")
private Team team;
@Embedded
private Period workPeriod;
@Embedded
private Address homeAddress;
}
이렇게 하면 테이블은 그대로 생성되고 조금 더 객체지향스럽게 사용할 수 있다.
JpaMain에서 다음과 같이 사용할 수 있다.
try {
Member member = new Member();
member.setUsername("hello");
member.setHomeAddress(new Address("city", "street", "100"));
member.setWorkPeriod(new Period());
em.persist(member);
tx.commit();
}
다음과 같이 값이 들어간 것을 볼 수 있다.
03. 임베디드 타입과 테이블 매핑
임베디드 타입과 테이블 매핑
임베디드 타입은 엔티티의 값일 뿐이다.
임베디드 타입을 사용하기 전과 후에 매핑하는 테이블은 같다.
객체와 테이블을 아주 세밀하게 매핑하는 것이 가능하다.
잘 설계한 ORM 애플리케이션은 매핑한 테이블의 수보다 클래스의 수가 더 많다.
DB 입장에서 달라질 것은 없고, 매핑이 달라지는 것이다. 객체는 데이터 뿐만 아니라 메소드(기능) 도 관리한다.
04. 임베디드 타입과 연관관계
임베디드 타입과 연관관계
Member 엔티티는 Address와 PhoneNumber라는 임베디드 타입을 갖는다.
Address는 Zipcode 라는 임베디드 타입을 갖는다.
PhoneNumber는 PhoneEntity라는 엔티티를 가질 수 있다.
05. 임베디드 타입의 장점
임베디드 타입의 장점
재사용이 가능하다. 응집도가 높다.Period.isWork()
처럼 해당 값 타입만 사용하는 의미 있는 메소드를 만들 수 있다.
임베디드 타입을 포함한 모든 값 타입은 값 타입을 소유한 엔티티에 생명주기를 의존한다.
06. @AttributeOverride : 속성 재정의
한 엔티티에서 같은 값 타입을 사용하면?
컬럼 명이 중복된다. @AttributeOverrides
, @AttributeOverride
를 사용해서 컬럼명 속성을 재정의하면 된다.
Member 클래스 안에 두 개의 Address(homeAddress와 workAddress)가 있다고 가정하자. Member 클래스 내에서 다음과 같이 작성하면 repeated 오류가 나타난다. 아래는 예시 코드이다.
@Embedded
private Address homeAddress;
@Embedded
private Address workAddress;
이럴 때는 @AttributeOverrides
를 사용하면 된다.
@Embedded
private Address homeAddress;
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "city", column = @Column(name = "WORK_CITY")),
@AttributeOverride(name = "street", column = @Column(name = "WORK_STREET")),
@AttributeOverride(name = "zipcode", column = @Column(name = "WORK_ZIPCODE"))
})
private Address workAddress;
따로 설정해둔 컬럼명이 반영된 것을 볼 수 있다.
임베디드 타입의 값이 null이면 매핑한 컬럼 값은 모두 null이다.
'JPA' 카테고리의 다른 글
값 타입의 비교 (0) | 2024.01.16 |
---|---|
값 타입과 불변 객체 (2) | 2024.01.15 |
기본값 타입 (2) | 2024.01.14 |
영속성 전이(CASCADE)와 고아 객체 (0) | 2024.01.14 |
즉시 로딩과 지연 로딩 (2) | 2024.01.12 |