[JPA] 임베디드와 컬렉션 값 타입

시나브로·2021년 5월 31일
0

JPA

목록 보기
10/12
post-thumbnail

1. Embedded Type


  Embedded Type은 응집도를 높히기 위해 자바 기본값 타입들을 한데 묶어 사용자가 임의로 생성한 Type을 말한다.


1.1 기본 사용 예제


Member.class


@Entity
public class Member {

    @Id
    @GeneratedValue
    private Long id;

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

  Member Entity에 주소 관련 컬럼이 위와 같이 정의되어있을 떄, Member가 주소관련 세부 상세 데이터들을 하나하나 관리하고 있는 것은 응집력을 떨어뜨린다. 이를 다음과 같이 변경할 수 있다.


Member.class


@Entity
public class Member {

    @Id
    @GeneratedValue
    private Long id;

    @Embedded
    private Address address;
    
    ...

Address.class


@Embeddable
public class Address {

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

정의된 타입을 사용해 응집도를 높혔을 뿐만 아니라, 재사용성도 높아졌다. 또한, 해당 값 타입만 사용하는 의미 있는 메소드를 만들어 사용할 수 있다.

  • 기본 생성자 필수
  • 컴포지션 관계로 구현된다
  • Table에는 변동사항이 없으며, 객체 지향적으로 관리 부분만 수정된다
  • @Embeddable, @Embedded 둘 중 하나는 생략 가능
  • Embeddable Class 내부에 연관관계도 포함 가능하다
  • 다른 Entity에서 재사용할 때, 같은 인스턴스 공유하는 점을 주의하자. 값을 변경했을 때, 참조되는 다른 컬럼의 데이터들도 일괄 변경된다.
    • 이 부분을 근본적으로 방지하기 위해 setter를 구현하지 않는 방법도 있다
  • 인스턴스를 활용하기 때문에 값 비교를 할 시, equals()를 재정의해 비교해야한다

1.2 속성 재정의


  한 Entity 내에 Embedded Type을 중복으로 사용해 재정의가 필요하다면 @AttributeOverride를 사용하면 된다


Member.class


@Entity
public class Member {

    @Id
    @GeneratedValue
    private Long id;

    @Embedded
    private 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")),
            
    })
    private Address companyAddress;
    
    
    ...

  • 딱 봐도 지저분해지니 꼭 필요한 상황이 아니면 지양하도록 하자



2. 값 타입 컬렉션


  단순한 값 타입 하나 이상을 저장하는 기능을 지원하기 위해 @ElementCollection@CollectionTable이 존재한다.


2.1 기본 사용 예제


Member.class


@Entity
public class Member {

    @Id
    @Column(name = "MEMBER_ID")
    private Long id;


    @ElementCollection
    @CollectionTable(name = "FAVORITE_FOODS", joinColumns =
    @JoinColumn(name = "MEMBER_ID"))
    @Column(name="FOOD_NAME")
    private Set<String> favoriteFoods = new HashSet<String>();

    @ElementCollection
    @CollectionTable(name = "ADDRESS", joinColumns =
    @JoinColumn(name = "MEMBER_ID"))
    private List<Address> addressHistory = new ArrayList<Address>();

    ...
  • DB에서는 컬렉션 데이터를 저장한다는 개념이 없다. 따라서 해당 어노테이션을 사용하면 별도의 테이블이 추가되어 매핑하게 된다.
  • @CollectionTable을 생략하면 기본값을 사용해 매핑한다.
    • 기본값은 {Entity 이름}_{Collection 속성 이름}
  • 수정 사항 관련

    • 임베디드 값 타입 컬렉션을 수정할 때는 불변성을 위해 기존인스턴스를 제거한 뒤 새로운 인스턴스를 등록해야한다.

    ex)

         addressHistory.remove(new Address("경기도", "기존 주소", "1234"));
          addressHistory.add(new Address("경기도", "기존 주소", "1234"));  
    • 위와 같이 값 타입 컬렉션에 변경사항이 발생하면, 해당 인스턴스를 삭제한 뒤 재등록해야한다는 점 때문에 해당 매핑보단 일대다 관계를 고려해야한다.



3. 마무리


  • Entity

    • 식별자 존재
    • 생명 주기 존재
    • 공유 가능
  • 값 타입

    • 식별자 없음
    • 생명 주기 Entity에 의존
    • 공유 가능하나 하지 않는 것을 지향






참고 도서

  • 자바 ORM 표준 JPA 프로그래밍 - 김영한
profile
Be More!

0개의 댓글