본문 바로가기
JPA

JPA 임베디드 타입

by khds 2021. 7. 22.

JPA의 데이터 타입은 크게 값 타입과 엔티티 타입으로 나눈다. 값 타입은 기본값 타입, 임베디드 타입(복합 값 타입), 컬렉션 값 타입으로 나뉘고 엔티티 타입은 @Entity로 정의하는 객체이다. 

기본 값 타입은 자바 기본 타입(ex. int, double), 래퍼 클래스(ex. Integer), String 로 구성된다.

 

먼저 임베디드 타입부터 설명하겠다. 임베디드 타입은 JPA에서 새로운 값 타입을 정의할 수 있도록 구현한 것이다. 즉 임베디드 타입도 int나 double와 같은 값 타입 이라는 것이다. 아래의 예시를 보자.

 

@Entity
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Builder
public class Article {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="article_id", nullable = false)
    private Long id;

    @ManyToOne
    @JoinColumn(name="user_id")
    private User user;

    @Column(nullable = false)
    private String title;

    @Lob
    @Column(nullable = false)
    private String content;

    @Embedded
    private Date date;

    @CreationTimestamp
    private Timestamp createdDate;

}

 

@Embeddable
public class Date {

    @Column(nullable = false)
    private int year;

    @Column(nullable = false)
    private int month;

    @Column(nullable = false)
    private int day;

    public Date(){}
    public Date(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }
}

 

위에서 보듯이 article 객체는 Date라는 값을 가진다. Date 값은 자바에서 사용되는 Date객체가 아니라 날짜를 표현하기 위해 임의적으로 붙인 명칭이다. 이는 Date 안에 year, month, day 3가지를 가진 것과 같다. 실제로 DB에는 Date 대신 year, month, day 가 들어가 있기에 Date로 표기하든 안하든 DB에는 똑같이 저장된다. 즉, 이는 성능문제없이 가독성을 향상시킬 수 있다. 여기서 주의할 점은 Date는 객체이며 값 타입이고 엔티티의 값일 뿐이지 엔티티 타입이 아니라는 것이다. 그리고 생성자는 필수로 있어야 한다. 

 

임베디드 타입을 만들기 위에선 위의 예시에서와 같이 @Embeddable, @Embedded 를 붙여서 만들 수 있다. 둘 중에 하나는 생략해도 된다.

 

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

 

임베디드 타입은 값타입을 포함하거나 엔티티를 참조할 수 있다. 즉 @Embeddable로 만든 임베디드 타입안에 일반적인 값 타입 뿐만 아니라 임베디드 타입을 포함할 수 있고 엔티티도 참조할 수 있다는 것이다. 

간단히 생각해보면 최초의 @Embedded로 지정된 곳에 여러개의 값 혹은 엔티티를 가독성있기 묶어서 표현한다는 것이다. 그렇기에 성능적으로는 떨어지는 일 없이 가독성이 크게 향상될 뿐이다. 

참고로 값을 가져올 때는 단순히 article.getDate().getYear() 로 가져올 수있고 집어넣을 때는 setDate(new Date(year, month, day)) 와 같이 단순하게 집어넣을 수 있다.

 

임베디드 타입에 정의한 매핑정보를 재정의하기 위해서 @AttributeOverride 라는 것을 사용할 수 있다. 아래의 예시를 보자 .

 

  @Embedded
  private Date preDate;
      
  @Embedded
  private Date nextDate;

 

위와 같이 같은 Date 타입으로 두개의 임베디드 타입을 지정했다. 이전 날짜와 다음 날짜를 같은 타입으로 표현하기 위햇 위와 같이 지정한 것인데 문제는 테이블에 매핑하는 컬럼명이 중복되는 것이다. 이를 해결하기 위한 것이 @AttributeOverride이다. 아래의 수정된 예시를 보자.

 

@Embedded
private Date preDate;

@Embedded
@AttributeOverrides({
    @AttributeOverride(name = "year", column = @Column (name = "NEXT_YEAR")),
    @AttributeOverride(name = "month", column = @Column (name = "NEXT_MONTH")),
    @AttributeOverride(name = "day", column = @Column (name = "NEXT_DAY"))
})
private Date nextDate;

 

위와 같이 표시한다면 article table에는 YEAR, MONTH, DAY, NEXT_YEAR, NEXT_MONTH, NEXT_DAY 6가지가 들어가게 된다.  여기서 주의할 점은 @AttributeOverides 는 엔티티에 설정해야 한다는 것이다. 임베디드 타입이 임베디드 타입을 가지고 있어도 엔티티에 설정해야 한다. 

 

참고

자바 ORM 표준 JPA 프로그래밍 - 김영한