본문 바로가기
Programming/Spring

[JPA] 엔티티타입 vs 값타입

by peter paak 2021. 3. 3.
728x90

종류

엔티티 타입

  • @Entity
  • PK를 가진다
  • 데이터가 변해도 식별자계속 추적가능한 것

값 타입

  • int, string...
  • PK가 없다 (값 그 자체이므로...)
  1. 기본값 타입 (int, Integer, String...)
  2. 임베디드 타입 (사용자가 정의한다)
  3. 컬렌션 타입 (사용자가 정의한다)

1. 기본값

  • int, String 등의 기본타입
  • 절대 공유되어서는 안되고 복사만 가능
  • immutable해야한다

2. 임베디드 타임

class Line {

        @Embedded
        private Sections sections;
}

@Embeddable
class Sections {

    private List<Section> sections
}
  • embed된 객체의 멤버만 가져와서 사용
  • 그냥 엔티티의 값이다

장점

  • 재사용 가능하다
  • 응집도가 높아진다
  • @Embeddable을 선언한 엔티티의 생명주기에 의존한다

왜 사용하는가?

  • 사용 전 후의 테이블의 수는 같다
  • 잘 매핑한 ORM은 테이블 수보다 클래스가 더 많다
  • 특히 List를 일급 객체로 사용할 때 유용하다
  1. @Embeddable
    • embed할 엔티에 사용
  2. @Embedded
    • 부모 엔티티에 @embeddable 태그가 붙은 엔티티를 적용시 사용
  3. 기본 생성자 필수

@AttributeOverrides

  • 한 엔티티에서 같은 값 타입을 사용할 경우
  • 컬럼명이 중복될 경우

@AttributeOverride

  • 구체적인 컬럼명 지정
@Embedded
@AttributeOverrides({
        @AttributeOverride(name="city", column = @Column(name="HOME_CITY")),
        @AttributeOverride(name="street", column = @Column(name="HOME_STREET")),
        @AttributeOverride(name="zipcode", column = @Column(name="HOME_ZIPCODE"))
})
private Address homeAddress;

@Embedded
private Address workAddress;

값 타입 복사

  • 값타입을 공유하는 것은 위험하다
  • 대신 값타입을 복사해서 사용할 수는 있다
// 값을 복사
Address copyAddress = new Address(homeAddress.getCity(), homeAddress.getStreet(), homeAddress.getZipcode());

Customer customer2 = new Customer();
customer2.setUsername("customer2");
customer2.setHomeAddress(copyAddress);
customer2.setWorkPeriod(new Period());
em.persist(customer2);

// 첫번째 customer의 city만 newCity로 바꾸고 싶어
customer1.getHomeAddress().setCity("newCity");

값타입 컬렉션

  • 데이터베이스는 기본적으로 컬렉션을 넣을 수 없다
  • 1대다 매핑만 가능
  • 멀티 셀렉트 할 때 사용
  • 추적할 필요도 없고 값이 바껴도 업데이트 할 필요없을 때
  • 웬만하면 쓰지마라... ⇒ 1대다 관계 + Cascade + orphanRemoval 쓰자...
@ElementCollection
@CollectionTable(name = "FAVORITE_THEME", joinColumns = @JoinColumn(name = "USER_ID"))
@Column(name = "FAVORITES")
private Set<String> favorites = new HashSet<>();

@ElementCollection

  • Collection 자료구조에 사용되는 어노테이션
  • 데이터베이스는 리스트를 컬럼으로 가질 수 없으므로 테이블을 추가 생성한다
  • 부모_자식의 형식으로 임의의 테이블과 컬럼명을 자동으로 지어준다

@CollectionTable

  • @ElementCollection의 테이블과 컬럼명을 지정할 수 있다

장점

  • 재사용 가능
  • 높은 응집도
  • 값 타입만 사용하는 메소드 사용가능
  • 값 타입을 소유한 엔티티의 생명주기에 의존
  • 객체 지향적으로 사용 가능
  • 잘 설계한 ORM 어플리케이션은 매핑한 테이블 수보다 클래스 수가 더 많다
  • 현업에서 왕창 쓰는 것은 아닌데...
  • 무튼 좋다 잘 사용하자
  • 절대 공유되어서는 안된다!한군데에서만 쓰자
  • 두 객체에서 공유하고 싶다면 엔티티로 만들어야 한다
  • 항상 값을 복사해서 사용하면 공유 참조로 발생하는 부작용을 피할 수 있다

한계

  1. 값 타입은 자바의 기본타입이 아니라 객체 타입이다
  2. 객체의 공유 참조를 피할 수 없다
    • 공유를 하지말고 복사를 하자
  3. 불변 객체! 로 만든다
    • 객체 타입을 수정 못하도록 부작용 전면차단
    • 생성 시점 이후 값을 절대 바꾸지 않도록 변경
  4. 값타입은 동일성(==) 보다는 동등성(equals) 비교
    • eqauls 메소드를 적절하게 재정의 ⇒ 자동으로 만들어 주는거 써라...
    • 근데 현업에서는 eqauls 비교할 일이 별로 없다...

그럼 값타입 컬렉션 언제쓸까

  1. 진짜 단순할때
  2. 멀티 셀렉트
    • 메뉴 선택할 때 멀티 셀렉트할 때만
    • 혹은 x, y 좌표..
    • ["play","food","game"]...
    • 추적할 필요도 없고 값이 바껴도 업데이트 칠 필요없을 때
    • 왠만하면 엔티티사용하고 왠만하면 값타입 엔티티 쓰지마라
728x90