[JPA] 임베디드 타입

최종윤·2022년 11월 27일

JPA

목록 보기
1/15
post-thumbnail

임베디드 타입

int, String과 같은 값타입인 임베디드 타입을 정의해서 사용할 수 있다.

Member 에 id,name, startDate, endDate, city,street,zipcode와 같이
필드가 있다고 하면 근무 시작일과 우편번호는 아무런 관련이 업습니다. 따라서
이름, 근무기간, 집 주소를 가진다고 하는 것이 더 간결합니다.
회원이 상세한 데이터를 그대로 가지고 있는 것은 객체지향적이지 않으면 응집력만 떨어뜨립니다.

Member id,name,
@Embedded workPeriod,
@Embedded homeAddress
로 하고 임베디드 타입에 @Embeddable을 붙여 정의합니다

@Embeddable workPeriod {
@Temporal(TemporalType.DATE)
Date startDate
..
isWork(Date date){
값 타입을 위한 메서드를 정의할 수 있다.
}

@Embeddable Address{
@Column(name="city")
city
...
}

임베디드 타입 사용법

@Embeddable을 정의하는 곳에 표시
@Embedded를 사용하는 곳에 표시
임베디드 타입은 기본 생성자가 필수
임베디드 타입을 포함한 모든 값 타입은 엔티티의 생명주기에 의존하므로 엔티티와
임베디드 타입 관계를 UML로 표현하면 컴포지션 관계가 됩니다.
하이버네이트는 임베디드 타입을 컴포넌트라 합니다.

임베디드 타입의 장점

재사용
높은 응집도
Period 객체의 isWork() 메서드 처럼 해당 값 타입만 사용하는 의미있는 메서드를 만들 수 있습니다.

임베디드 타입과 테이블 매핑

임베디드 타입은 엔티티의 값일 뿐입니다.
따라서 값이 속한 엔티티의 테이블에 매핑합니다 . 예제에서 임베디드 타입을 사용하기 전과
후에 매핑하는 테이블은 같습니다.
임베디드 타입 덕분에 객체와 테이블을 아주 세밀하게 매핑하는 것이 가능합니다. 잘 설계한 ORM앱은 매핑한 테이블의 수보다 클래스의 수가 더 많습니다.

임베디드 타입과 연관관계

임베디드 타입은 값 타입을 포함하거나 엔티티를 참조할 수 있습니다.

@Entity
public class Member {

@Embedded
Address address; // 임베디드 타입 포함
@Embedded
PhoneNumber phoneNumber; // 임베디드 타입 포함
// ...
}

@Embeddable
public class Address {
String street;
String city;
String state;
@Embedded
Zipcode zipcode; // 임베디드 타입 포함
}

@Embeddable
public class Zipcode {
String zip;
String plusFour;
}

@Embeddable
public class PhoneNumber {

String areaCode;
String localNumber;

@ManyToOne
PhoneServiceProvider provider; // 엔티티 참조
}

@Entity
public class PhoneServiceProvider {
@Id
String name;
// ...
}

값 타입인 Address가 값 타입인 Zipcode를 포함하고, 값 타입인 PhoneNumber가 엔티티 타입인 PhoneServiceProvider를 참조합니다.

AttributeOverride :속성 재정의

임베디드 타입에 정의한 매핑정보를 재정의하려면 엔티티에 @AttributeOverride를 사용하면 됩니다.
예를 들어 회원에게 주소가 하나 더 필요하면 어떻게 해야 할까요?
// 같은 임베디드 타입을 가지고 있는 회원
@Entity
public class Member {

@Id @GeneratedValue
private Long id;
private String name;

@Embedded
Address homeAddress;

@Embedded
Address companyAddress;
}
위 코드의 문제점은 테이블에 매핑하는 컬럼명이 중복되는 것입니다. 이때는 아래와 같이 @AttributeOverrides를 사용해서 매핑정보를 재정의해야 합니다.

@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 TABLE MEMBER (
COMPANY_CITY varchar(255),
COMPANY_STREET varchar(255),
COMPANY_ZIPCODE varchar(255),
city varchar(255),
street varchar(255),
zipcode varchar(255),
...
)
@AttributeOverride 를 사용하면 어노테이션을 너무 많이 사용해서 엔티티 코드가 지저분해집니다. 다행히도 한 엔티티에 같은 임베디드 타입을 중복해서 사용하는 일은 많지 않습니다.

@AttributeOverrides는 엔티티에 설정해야 합니다. 임베디드 타입이 임베디드 타입을 가지고 있어도 엔티티에 설정해야 합니다.

임베디드 타입과 null

임베디드 타입이 null이면 매핑한 컬럼 값은 모두 null이 됩니다.
member.setAddress(null);
em.persist(member);
회원 테이블의 city,street,zipcode는 모두 null이 됩니다.

profile
https://github.com/jyzayu

0개의 댓글