ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JPA - Embedded Type
    🌱 spring 2022. 11. 2. 17:23

    🗂 JPA의 데이터 타입 분류


    엔티티 타입

    • @Entity로 정의하는 객체
    • 데이터가 변해도 식별자로 지속해서 추적 가능

    값 타입

    • Integer, String 처럼 단순히 값으로 사용하는 자바 기본 타입이나 객체를 의미
    • 식별자가 없고 값만 존재 → 변경시 추적 불가

    값 타입 분류

    • 기본 값 타입
      • 자바 기본 타입 (int, double)
      • 래퍼 클래스(Integer, Long)
      • String
    • 임베디드 타입
    • 컬렉션 값 타입

    임베디드 타입(Embedded Type) ❓


    복합 값 타입을 의미한다

    • 새로운 값 타입을 직접 정의할 수 있다.
    • JPA는 임베디드 타입 이라고 불려진다
    • 주로 기본 값 타입을 모아서 만들어서 복합 값 타입이라고 한다.

    직접 정의한 임베디드 타입도 int, String 처럼 값 타입이다!!!

    사용방법

    • @Embeddeable
      • 값 타입을 정의하는 곳에 표시
      • 임베디드 타입을 사용하기 위해 생성한 Class에 표시
    • @Embedded
      • 값 타입을 사용하는 곳에 표시
      • 임베디드 타입을 사용하는 Entity에 표시

    임베디드 타입은 기본 생성자가 필수다!!

     

    임베디드 타입을 포함한 모든 값 타입은 엔티티의 생명주기에 의존한다

    → 엔티티와 임베디드 타입 관계는 컴포지션(Composition) 관계가 된다.

    예시

    사용하기 전

    // 임베디드 타입 사용하지 않았을 때
    @Entity
    public class Member {
      
      @Id @GeneratedValue
      private Long id;
      private String name;
      
      // 근무 기간
      @Temporal(TemporalType.DATE)
      Date startDate;
      @Temporal(TemporalType.DATE)
      Date endDate;
      
      // 집 주소 표현
      private String city;
      private String street;
      private String zipcode;
      // ...
    }
    • 평범한 회원 엔티티

    회원 엔티티는 [ 이름, 근무 시작일, 근무 종료일, 주소 도시, 주소 번지, 주소 우편 번호 ] 를 가진다

    위 보다 아래의 설명이 더 정확하다.

    회원 엔티티는 [ 이름, 근무 기간, 집 주소 ] 를 가진다.

    회원이 상세한 데이터를 그대로 가지고 있는 것은 객체지향적 ❌, 응집력만 떨어뜨린다.

     

    사용한 후

    Member.java

    // 임베디드 타입 사용
    @Entity
    public class Member {
      
      @Id @GeneratedVAlue
      private Long id;
      private String name;
      
      @Embedded
      private Period workPeriod;	// 근무 기간
      
      @Embedded
      private Address homeAddress;	// 집 주소
    }

    Period.jave

    // 기간 임베디드 타입
    @Embeddable
    public class Peroid {
      
      @Temporal(TemporalType.DATE)
      Date startDate;
      @Temporal(TemporalType/Date)
      Date endDate;
      // ...
      
      public boolean isWork (Date date) {
        // .. 값 타입을 위한 메서드를 정의할 수 있다
      }
    }

    Address.java

    @Embeddable
    public class Address {
      
      @Column(name="city") // 매핑할 컬럼 정의 가능
      private String city;
      private String street;
      private String zipcode;
      // ...
    }

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

    member.setAddress(null); // null 입력
    em.persist(member);
    

    회원 테이블의 주소와 관련된 모든 컬럼이 null이 된다.

     

    장점

    1. 재사용이 가능하다
    2. 높은 응집도를 가진다
    3. 값 타입만 사용하는 의미 있는 메서드를 만들 수 있다.
      • ex) Period 객체의 isWork() 메서드

     

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

    임베디드 타입은 엔티티의 값일 뿐이다.

    • 따라서 값이 속한 엔티티의 테이블에 매핑한다.

    ⇒ 엔티티 안에서 임베디드 타입을 사용해 클래스를 나누는 것은 데이터베이스 테이블의 컬럼과 전혀 관계가 없다.

    ⇒ 임베디드 타입을 사용하기 전, 후의 테이블 차이는 없다.

     

    따라서 잘 설계된 ORM 애플리케이션은 매핑한 테이블의 수보다 클래스의 수가 더 많다.

     

    임베디드 타입과 연관관계

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

    @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를 사용해야 한다.
    @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 TABLE MEMBER (
      COMPANY_CITY varchar(255),
      COMPANY_STREET varchar(255),
      COMPANY_ZIPCODE varchar(255),
      city varchar(255),
      street varchar(255),
      zipcode varchar(255),
      ...
    )

    @AttributeOverrides 는 엔티티에 설정을 해야한다.

    임베디드 타입이 임베디드 타입을 가지고 있더라도 엔티티에 설정을 해야 한다.

     

    참고 자료

    https://tall-developer.tistory.com/m/16

    https://velog.io/@conatuseus/JPA-임베디드-타입embedded-type-8ak3ygq8wo

    https://pugyu.tistory.com/91

    '🌱 spring' 카테고리의 다른 글

    애플리케이션 컨텍스트와 빈팩토리  (0) 2022.11.16
    JPA - @ElementCollection  (0) 2022.11.02
    Spring Scheduler  (0) 2022.10.24
    Filter, Interceptor  (0) 2022.10.11
    OSIV 🧐  (0) 2022.10.11

    댓글

Designed by Tistory.