JPA 값 타입 - 임베디드 타입

2022. 7. 12. 21:30·공부/JPA
반응형

출처 : 자바 ORM 표준 JPA 프로그래밍 인프런 강의

 

JPA 게시글은 대부분 인프런의 김영한님의 강의인 '자바 ORM 표준 JPA 프로그래밍' 기반으로 내용을 정리했습니다.

 

임베디드 타입(복합 값 타입)

  • 새로운 값 타입을 직접 정의할 수 있음
  • JPA는 임베디드 타입(embedded type)이라 함
  • 주로 기본 값 타입을 모아서 만들어서 복합 값 타입이라고도 함
  • int, String과 같은 타입 → 추적 불가능

 

예제(회원)

  • 회원은 이름, 근무 시작일, 근무 종료일, 주소 도시, 주소 번지, 주소 우편번호를 가진다.

회원 엔티티를 보면 몇 개의 필드를 하나로 합쳐 공통화 할 수 있는 부분들이 보인다.

  • workPeriod : startDate + endDate
  • homeAddress : city + street + zipcode

뭔가 어려워보이지만 그냥 공통화 할 수 있는 부분을 따로 빼서 클래스화 한 것이다.

 

임베디드 타입 사용법

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

 

임베디드 타입 장점

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

 

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

DB 입장에서는 임베디드 타입을 사용하던 안하던 회원테이블은 변함없이 똑같다. 임베디드 타입을 사용하면 대신 매핑 작업이 추가로 들 뿐이다. 매핑 작업이 추가로 필요함에도 불구하고 임베디드 타입을 굳이 사용하는 이유는 객체 입장에서는 메서드, 즉 행위까지 생각해야하고 임베디드 타입을 사용하면 이런 부분에서 많은 이득을 가져갈 수 있다.

Member.class

@Entity
public class Member  {

    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

    @Column(name = "USERNAME")
    private String username;


    // 기간
    @Embedded
    private Period workPeriod;

    // 주소
    @Embedded
    private Address homeAddress;
}

Period.class

@Embeddable
public class Period {

   private LocalDateTime startDate;
   private LocalDateTime endDate;

    public Period() {
    }
	
    // getter/setter
}

Address.class

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

    public Address() {
    }
    
    // getter/setter
}

출력 로그

Hibernate: 
    
    create table Member (
       MEMBER_ID bigint not null,
        city varchar(255),
        street varchar(255),
        zipcode varchar(255),
        USERNAME varchar(255),
        endDate timestamp,
        startDate timestamp,
        primary key (MEMBER_ID)
    )

 

사실 @Embeddable, @Embedded 둘 중 하나만 사용해도 알아서 적용되지만 웬만하면 두 개 다 사용하는 걸 권장한다. Member 객체에 기간과 주소와 관련된 필드를 다 적어도, 임베디드 타입을 사용해도 위 출력 로그가 동일하게 전송된다.

 

실행 클래스

Member member = new Member();
member.setUsername("member");
member.setHomeAddress(new Address("city", "street", "100"));
member.setWorkPeriod(new Period());

em.persist(member);
tx.commit();


// 출력 로그
Hibernate: 
    call next value for hibernate_sequence
Hibernate: 
    /* insert hellojpa.Member
        */ insert 
        into
            Member
            (city, street, zipcode, USERNAME, endDate, startDate, MEMBER_ID) 
        values
            (?, ?, ?, ?, ?, ?, ?)

Insert 쿼리가 전송되고, DB에도 값이 잘 저장되어 있는 모습을 볼 수 있다.

 

정리!

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

 

 

임베디드 타입과 연관관계

여기에서 특이한 점은 Value인 PhoneNumber가 Entity인 PhoneEntity를 가지고 있다는 점이다. 위에서 했던 예제에서 Address에서도 Member 객체를 불러올 수 있기 때문에 가능한 일이다.

 

@AttributeOverride : 속성 재정의

한 엔티티(클래스) 안에서 같은 값 타입을 사용할 수 있을까? 회원의 엔티티에 집 주소 외에 회사 주소를 저장해야한다고 가정해보자.

@Embedded
private Address homeAddress;

@Embedded
private Address workAddress;

이렇게 필드를 만들고 애플리케이션을 실행해보면 에러가 발생한다.

이런 경우 @AttributeOverrides와 @AttibuteOverride로 해결할 수 있다.

@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이면 매핑한 컬럼 값은 모두 null이다.

만약 Member 클래스에서 Preriod의 값을 null로 주었다면, Preriod 클래스 안에 있는 모든 필드엔 null 값이 저장된다.

반응형
저작자표시 비영리 변경금지 (새창열림)
'공부/JPA' 카테고리의 다른 글
  • JPA 값 타입 - 값 타입의 비교
  • JPA 값 타입 - 값 타입과 불변 객체
  • JPA 값 타입 - 기본값 타입
  • JPA 프록시와 연관관계 - 영속성 전이(CASCADE)와 고아 객체
데부한
데부한
어차피 할 거면 긍정적으로 하고 싶은 개발자
    반응형
  • 데부한
    동동이개발바닥
    데부한
  • 전체
    오늘
    어제
    • 분류 전체보기 (307)
      • 방통대 컴퓨터과학과 (27)
        • 잡담 (9)
        • 3학년1학기 (17)
      • 프로젝트 및 컨퍼런스 회고 (1)
        • 프로젝트 (4)
        • 한이음 프로젝트 (0)
        • 회고 (3)
      • 공부 (165)
        • Spring (37)
        • JPA (71)
        • 인프런 워밍업 클럽_BE (10)
        • Java (6)
        • React.js (27)
        • 넥사크로 (11)
        • 기타 (3)
      • 알고리즘 (85)
        • 알고리즘 유형 (10)
        • 알고리즘 풀이 (57)
        • SQL 풀이 (18)
      • 에러 해결 (13)
      • 잡담 (7)
        • 국비교육 (2)
        • 구매후기 (5)
        • 진짜 잡담 (0)
  • 블로그 메뉴

    • Github
    • Linkedin
    • 홈
    • 방명록
    • 글쓰기
    • 관리
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    운영체제
    스프링부트
    MSA
    springboot
    Java
    RESTful
    방통대
    react
    알고리즘
    QueryDSL
    IT
    전자정부프레임워크
    egov
    프로그래머스
    에러해결
    Spring
    JPA
    프론트엔드
    인프런
    토비의스프링부트
    기출문제
    개발자
    SpringBoot를 이용한 RESTful Web Service 개발
    백준
    SQL
    코딩테스트
    oracle
    넥사크로
    자바스크립트
    토이프로젝트
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
데부한
JPA 값 타입 - 임베디드 타입
상단으로

티스토리툴바