값 타입

2023. 9. 22. 14:43JPA

반응형

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

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

 

1. 기본값 타입
@Entity
public class Member {
   
   @Id @GeneratedValue
   private Long id;
   
   private String name;
   private int age;
   ...
}

Member 엔티티에서 String, int가 값 타입이다. Member 엔티티는 id라는 식별자 값도 가지고 생명주기도 있지만 값 타입인 name, age 속성은 식별자 값도 없고 생명주기도 회원 엔티티에 의존한다. 따라서 회원 엔티티 인스턴스를 제거하면 name, age 값도 제거된다. 그리고 값 타입은 공유하면 안된다. 

 

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

새로운 값 타입을 직접 정의해서 사용한다. 중요한 것은 직접 정의한 임베디드 타입도 int, String 처럼 값 타입이라는 것이다.

@Entity
public class Member {

   @Id @GeneratedValue
   private Long id;
   
   private String name;
   
   //근무 기간
   @Temporal(TemporalType.DATE) java.util.Date startDate;
   @Temporal(TemporalType.DATE) java.util.Date endDate;
   
   //주소
   private String city;
   private String street;
   private String zipcode;
   ...
}

회원이 상세한 데이터를 가지고 있는것은 객체지향적이지 않으며 응집력만 떨어뜨린다. 대신에 근무 기간, 주소 같은 타입이 있다면 코드가 더 명확해질 것이다.

@Entity
public class Member {
   
   @Id @GeneratedValue
   private Long id;
   private String name;
   
   @Embedded Period workPeroid; //근무 기간
   @Embedded Address home Address; //주소
   ...
}

//근무 기간 임베디드 타입
@Embeddable
public class Period {

   @Temporal(TemporalType.DATE) java.util.Date startDate;
   @Temporal(TemporalType.DATE) java.util.Date endDate;
   ...
   
   public boolean isWork(Date date) {
   // 값 타입을 위한 메소드를 정의할 수 있다.
   }
}

//주소 임베디드 타입
@Embeddable
public class Address {

   @Column(name="city") //매핑할 컬럼 지정 가능
   private String city;
   private String street;
   private String zipcode;
   ...
}

회원-컴포지션 관계 UML

임베디드 타입은 기본 생성자가 필수다. 임베디드 타입을 포함한 모든 값 타입은 엔티티의 생명주기에 의존하므로 엔티티와 임베디드 타입의 관계를 UML로 표현하면 컴포지션 관계가 된다.

 

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

회원-테이블 매핑

임베디드 타입을 쓰건 안쓰건 테이블에 매핑하는건 같다. 잘 설계한 ORM 애플리케이션은 매핑한 테이블의 수보다 클래스의 수가 더 많다.

 

@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 MEMBER (
   COMPANY_CITY varchar(255),
   COMPANY_STREET varchar(255),
   COMPANY_ZIPCODE varchar(255),
   city varchar(255),
   street varchar(255),
   zipcode varchar(255),
   ...
}
| id | name  | city         | street         | zipcode       | COMPANY_CITY   | COMPANY_STREET | COMPANY_ZIPCODE |
|----|-------|--------------|----------------|---------------|----------------|----------------|-----------------|
| 1  | John  | Home City    | Home Street    | Home Zipcode  | Company City   | Company Street | Company Zipcode |

@AttributeOverride를 사용하면 어노테이션을 너무 많이 사용해서 엔티티 코드가 지저분해진다. 한 엔티티에 같은 임베디드 타입을 중복해서 사용하는 일은 많지 않다.

반응형

'JPA' 카테고리의 다른 글

JPQL - (기본 문법, 쿼리 API, 페이징 API, 집합과 정렬)  (0) 2023.09.25
객체지향 쿼리 언어 소개  (0) 2023.09.22
영속성 전이: CASCADE  (0) 2023.07.31
즉시 로딩과 지연 로딩  (0) 2023.07.31
프록시  (0) 2023.07.28