JPA의 데이터 타입 - 값 타입, 엔티티 타입(2)

2022. 3. 26. 20:22JPA 기초

2-1) 기본 값 타입(primitive) - 이전 포스팅 참고

 

2-2) 임베디드 타입
임베디드 타입을 활용하면 새로운 값 타입을 직접 정의할 수 있다!!
int, String과 같은 값 타입이다. 주로 기본 값 타입을 모아 만들어서 복합 값 타입이라고도 한다.

ex) 회원 엔티티는 이름, 근무시작일, 근무 종료일, 주소 도시, 주소 번지, 주소 우편번호를 갖는다고 하자.
이 엔티티를 보면 근무 시작일-종료일 // 주소(도시, 번지, 우편번호) 묶고싶다는 생각이 들 것이다. 

변경하면 회원 엔티티는 이름, 근무 기간, 집 주소를 갖는다. 임베디드 타입을 사용하면 이렇게 묶어낼 수 있다.

 

    private LocalDateTime startDate;
    private LocalDateTime endDate;

    private String city;
    private String street;
    private String zipcode;

이전 코드의 경우 멤버라는 엔티티에 근무일, 집 주소가 흩어져 있다.

 

아래와 같이 변경 가능하다.

    @Embedded
    private Period workPeriod;

    @Embedded
    private Address homeAddress;

이후 Period, Address 클래스는

@Embeddable
public class Address {

    private String city;
    private String street;
    private String zipcode;

    public Address() {
    }

    public Address(String city, String street, String zipcode) {
        this.city = city;
        this.street = street;
        this.zipcode = zipcode;
    }

    public String getCity() {
        return city;
    }

    public String getStreet() {
        return street;
    }

    public String getZipcode() {
        return zipcode;
    }

}

 


-사용법
@Embeddable: 값 타입을 정의하는 곳에 표시한다.
@Embedded: 값 타입을 사용하는 곳에 표시한다.
참고로 따로 뽑아낸 클래스에는 기본 생성자가 필수로 존재해야 한다. 

강의에서 기본 생성자는 필수라고 하셨는데 이유는 모르겠다.. 검색해도 안나오네

 

기본 생성자 없이 코드를 실행시켰다.

INFO: HHH000182: No default (no-argument) constructor for class: hellojpa.Address (class must be instantiated by Interceptor)

다음과 같은 경고문이 떴고 쿼리문은 찍혀있지만, DB에는 아무런 변화가 없었다..

 

Hibernate 에서는 Reflection 으로 Entity Object 를 생성하기 때문에

모든 Entity 는 default constructor 를 갖고 있어야 하므로 저렇게 말씀하신 것 같다.

 

기본생성자의 주석을 풀고 실행하니 db에 반영되었다.

 

 

아무튼

이렇게 클래스로 따로 뽑아낸 경우

재사용이 가능하며(클래스로 뽑아냈으니) 클래스 내에 묶어놓았으니 응집도가 높다. 
클래스 내에서 해당 값 타입만 사용하는 의미있는 메소드를 만들수 있으며

임베디드 타입을 포함한 모든 값 타입은, 값 타입을 소유한 엔티티에 생명주기를 의존한다는 장점이 있다.

 

 

* 임베디드 타입을 사용하기 전과 후에 매핑하는 테이블은 같다. 
객체와 테이블을 세밀하게 매핑하는 것이 가능하다. 설계 시 모델링이 깔끔하게 떨어지고, 좀 더 객체지향적으로 코드를 작성할 수 있다!

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

 

 


만약 한 엔티티에서 같은 값 타입을 사용하면? 당연히 에러가 발생한다. 중복 매핑되었기 때문이다.

멤버라는 엔티티 내에서 아래처럼 같은 값 타입을 사용하면

@Embedded
    private Address homeAddress;

    @Embedded
    private Address workAddress;
  @Embedded
    private Address homeAddress;

    @Embedded
@AttributeOverrides({@AttributeOverride(name="city", column=@column("WORK_CITY"))}
    private Address workAddress;

@AttributeOverrides를 사용해 컬럼 명 속성을 모두 재정의해야 한다. 위에서는 city만 재설정 하였으나

street, zipcode도 컬럼명을 재정의 해야 한다.

그렇게 하면 재정의된 테이블에 새로운 컬림이 생성되며 그 컬럼으로 insert문이 나간다.