오봉이와 함께하는 개발 블로그

JPA - 임베디드 타입 본문

BE/JPA

JPA - 임베디드 타입

오봉봉이 2022. 6. 29. 01:10
728x90

임베디드 타입

  • 새로운 값 타입을 직접 정의할 수 있다.
  • JPA는 임베디드 타입(embedded type)이라 한다.
  • 주로 기본 값 타입을 모아서 만들기 때문에 복합 값 타입이라고도 한다.
  • int, String과 같은 값 타입

예를 들어 회원 엔티티는 아래와 같은 값을 가진다.
(이름, 근무 시작일, 근무 종료일, 주소 도시, 주소 번지, 주소 우편번호)

간단하게 작성하면 회원 엔티티는 아래와 같은 값을 가진다.
(이름, 근무 기간, 집 주소)

ERD는 다음과 같다.

임베디드 타입 사용법

  • @Embeddable : 값 타입을 정의하는 곳에 표시
  • @Embedded : 값 타입을 사용하는 곳에 표시
  • 기본 생성자는 필수다.

장점

  • 재사용
  • 높은 응집도
  • Period.isWork()처럼 해당 값 타입만 사용하는 의미 있는 메소드를 만들 수 있다.
  • 임베디드 타입을 포함한 모든 값 타입은, 값 타입을 소유한 엔티티에 생명주기를 의존한다.

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


DB 입장에서는 데이터만 잘 저장하면 되기 때문에 바뀔 것이 없다.
하지만 객체는 데이터뿐 아니라 메소드까지 가지고 있기 때문에 임베디드 타입에 공통 메소드를 작성해 간결함이나, 객체 지향을 유지하는 등 이득을 취할 수 있다.

  • 정리
    • 임베디드 타입은 엔티티의 값일 뿐이다.
    • 임베디드 타입을 사용하기 전과 후에 매핑하는 테이블은 같다.
    • 객체와 테이블을 아주 세밀하게 매핑하는 것이 가능하다.
    • 잘 설계한 ORM 애플리케이션은 매핑한 테이블의 수보다 클래스의 수가 더 많다.

코드

@Entity
@Getter @Setter
public class Member{
    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;
    @Column(name = "USERNAME")
    private String name;
    // Period
    private LocalDateTime startDate;
    private LocalDateTime endDate;
    // 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;
    @Column(name = "USERNAME")
    private String name;

    // Period
    @Embedded
    private Period workPeriod;
    // Address
    @Embedded
    private Address homeAddress;
}

@Embeddable
@Getter @Setter
public class Address {
    private String city;
    private String street;
    private String zipcode;

    public Address() { // 기본 생성자 필수
    }

    public Address(String city, String street, String zipcode) {
        this.city = city;
        this.street = street;
        this.zipcode = zipcode;
    }
}

@Embeddable
@Getter @Setter
public class Period {
    private LocalDateTime startDate;
    private LocalDateTime endDate;

    public Period() { // 기본 생성자 필수
    }

    public Period(LocalDateTime startDate, LocalDateTime endDate) {
        this.startDate = startDate;
        this.endDate = endDate;
    }
}

사용

Member member = new Member();
member.setName("Hello");
member.setHomeAddress(new Address("city", "address", "10000"));
member.setPeriod(new Period());

임베디드 타입과 연관관계


Member 엔티티는 Address라는 임베디드 타입을 가지고 있고 Address는 Zipcode라는 임베디드 타입을 들고 있다.
또 Member는 PhoneNumber라는 임베디드 타입을 가지고 있고, PhoneEntity라는 엔티티를 가지고 있다.
가능한 이유는 PhoneNumber에서 PhoneEntity를 FK로 가지고 있으면 되기 때문이다.

@AttributeOverride : 속성 재정의

만약 한 엔티티 안에서 같은 값 타입을 사용하면 어떻게 될까?

@Embedded
private Address homeAddress;
@Embedded
private Address workAddress;

컬럼명이 중복되는 오류가 발생한다.

이럴 때 @AttributeOverrides, @AttributeOverride를 사용해서 컬러 명 속성을 재정의하면 된다.

@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;

위와 같이 작성하면 WORK_CITY, WORK_STREET, WORK_ZIPCODE라는 컬럼이 Member 테이블에 추가된다.

임베디드 타입과 null

임베디드 타입의 값이 null이면 매핑한 컬럼 값은 모두 null이 된다.

@Embedded
private Period workPeriod = null;
출처 : 인프런 김영한 지식공유자님의 스프링 부트와 JPA 실무 완전 정복 로드맵 강의
728x90

'BE > JPA' 카테고리의 다른 글

JPA - 값 타입의 비교  (0) 2022.06.29
JPA - 값 타입과 불변 객체  (0) 2022.06.29
JPA - 기본값 타입  (0) 2022.06.29
JPA - 실전 예제 5 - 연관관계 관리  (0) 2022.06.28
JPA - 영속성 전이(CASCADE)와 고아 객체  (0) 2022.06.28
Comments