프레임워크(Framework)/JPA

[JPA] 기본값 타입과 임베디드 타입 - 값 타입 (1)

잇트루 2022. 12. 8. 02:20
반응형
본 내용은 온라인 강의 사이트 인프런의 김영한 님의 강의 내용이 포함되어 있습니다.
'자바 ORM 표준 JPA 프로그래밍 - 기본편'
 

자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의

JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., - 강의 소개 | 인프런

www.inflearn.com

 

Intro

JPA의 데이터 타입을 분류하면 엔티티 타입과 값 타입으로 구분할 수 있다.

 

엔티티 타입

  • @Entity로 정의하는 객체
  • 데이터가 변해도 식별자를 통해 지속해서 추적할 수 있다.
  • 예) 회원 엔티티의 키나 나이 등의 값을 변경해도 식별자로 인식 가능

 

 

값 타입

  • int, Integer, String처럼 단순히 값으로 사용하는 자바 기본 타입이나 객체
  • 식별자가 없고 숫자나 문자 같은 속성만 있어 변경 시 추적이 불가능하다.
  • 예) 숫자 100을 200으로 변경하면 완전히 다른 값으로 대체

 

 

값 타입은 다음 3가지로 나눌 수 있다.

  • 기본값 타입 : 자바 기본 타입, 래퍼 클래스, String
    • 자바에서 제공하는 기본 데이터 타입

 

  • 임베디드 타입(Embedded type, 복합 값 타입) : 좌표, 포지션 등
    • JPA에서 사용자가 직접 정의한 값 타입

 

  • 컬렉션 값 타입(Collection value type) : 기본값 타입이나 임베디드 타입을 저장할 수 있는 것
    • 하나 이상의 값 타입을 저장할 때 사용

 

 

기본값 타입

가장 단순한 자바에서 제공하는 기본 데이터 타입이다.

@Entity
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // 값 타입
    private String name;
    private int age;
    ...
}
  • String name, int age 등
  • 생명주기를 엔티티에 의존한다.
    • 회원을 삭제하면 이름, 나이 필드도 함께 삭제
  • 값 타입은 공유하면 안 된다.
    • 회원 이름 변경 시 다른 회원의 이름도 함께 변경되면 안 됨

 

 

기본값 타입 참고사항

  • 자바에서 int, double과 같은 기본 타입은 절대 공유되지 않는다.
    • a = b와 같이 b의 값을 복사하여 a에 입력한다.
  • Integer처럼 래퍼 클래스나 String 같은 특수한 클래스도 있다.
    • 공유 가능한 객체이지만 변경이 불가능하다.

 

 

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

임베디드 타입은 JPA에서 새로운 값 타입을 직접 정의해서 사용하는 것을 의미한다.

  • 주로 기본 값 타입을 모아서 만들어 복합 값 타입이라고도 함
  • 직접 정의한 임베디드 타입도 int, String과 같은 값 타입

 

 

임베디드 타입 사용 전

@Entity
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    
    // 근무 시간
    LocalDateTime startDate;
    LocalDateTime endDate;

    // 주소
    private String city;
    private String street;
    private String zipcode;

}
  • 회원 엔티티는 이름, 근무 시작일, 근무 종료일, 주소 도시, 주소 번지, 주소 우편번호를 가진다.
  • 상세한 데이터를 그대로 가지고 있는 것은 객체지향적이지 않으며 응집력을 떨어트린다.
    • 근무 시작일과 근무 종료일 → 근무 시간
    • 주소 도시, 주소 번지, 주소 우편번호 → 집 주소

 

 

임베디드 타입 사용법

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

 

 

임베디드 타입 사용

Member

@Entity
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    
    @Embedded
    Period workPeriod; // 근무 시간

    @Embedded
    Address homeAddress; // 집 주소

    // Getter
    // Setter
}
  • 회원 엔티티는 이름, 근무 시간, 집 주소를 가진다.

 

Period

@Embeddable
public class Period {

    private LocalDateTime startDate;
    private LocalDateTime endDate;

    public boolean isWork(LocalDateTime date) {
        ...
    }

    public Period() {
    }

    // Getter
    // Setter
}

 

Address

@Embeddable
public class Address {

    @Column(name = "city")
    private String city;
    private String street;
    private String zipcode;

    public Address() {
    }

    // Getter
    // Setter
}

 

임베디드 타입의 장점

  • 새로 정의한 값 타입들은 재사용이 가능하다.
  • 회원 엔티티가 더욱 의미 있고 높은 응집도로 변할 수 있게 되었다.
  • Period.isWork()와 같은 해당 값 타입만 사용하는 의미 있는 메서드를 만들 수 있다.
  • 임베디드 타입을 포함한 모든 값 타입은, 값 타입을 소유한 엔티티에 생명주기를 의존한다.

 

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

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

 

 

임베디드 타입과 연관관계

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

  • Member 엔티티는 Address 임베디드 타입과 Phone Number 임베디드 타입을 가지고 있다.
    • Address 임베디드 타입은 Zipcode라는 값을 가질 수 있다.
    • PhoneNumber 임베디드 타입은 PhoneEntity라는 엔티티를 가질 수 있다.

 

 

임베디드 타입 속성 재정의 - @AttributeOverride

  • 한 엔티티에서 같은 값 타입을 사용하면 컬럼명이 중복된다.
  • @AttributeOverrides, @AttributeOverride를 사용하여 컬럼 명 속성을 재정의한다.
@Entity
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "MEMBER_ID")
    private Long id;

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

    @Embedded
    private Period workPeriod;

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

    // Getter
    // Setter
}

 

임베디드 타입과 null

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

member.setAddress(null);
em.persist(member);
  • 회원 테이블의 주소와 관련된 CITY, STREET, ZIPCODE 컬럼은 모두 null
반응형