Search
Duplicate

값 타입(2/2)

값 타입의 비교

인스턴스가 달라도 그 안에 값이 같으면 같은 것으로 봐야 한다.
// primitive type 비교 int a = 10; int b = 10; System.out.println(a == b);//true // 임베디드 타입(인스턴스) 비교 Address a = new Address("서울", "AAA", 1000); Address b = new Address("서울", "AAA", 1000); System.out.println(a == b);//false
Java
복사
어째서 임베디드 타입의 ==비교는 false가 뜨는것인가? 당연하다. 인스턴스가 다르니 다른객체이기 때문이다.
그럼 어떻게 해야할까?
동일성(identity) 비교: 인스턴스의 참조 값을 비교, == 사용
동등성(equivalence)비교: 인스턴스의 값을 비교, equals() 사용
값 타입은 a.equals(b)를 사용해서 동등성 비교를 해야 한다.
값 타입의 equals()메소드를 적절하게 재정의 해준다(주로 모든 필드 사용)
@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Address address = (Address) o; return Objects.equals(city, address.city) && Objects.equals(street, address.street) && Objects.equals(zipcode, address.zipcode); } @Override public int hashCode() { return Objects.hash(city, street, zipcode); } ... ... ... // 임베디드 타입(인스턴스) 비교 Address a = new Address("서울", "AAA", 1000); Address b = new Address("서울", "AAA", 1000); System.out.println(a.equals(b));//true 이제 true가 된다.
Java
복사

값 타입 컬렉션

값 타입을 하나 이상 저장할 때 사용
@ElementCollection, @CollectionTable 사용
데이터베이스는 컬렉션을 같은 테이블에 저장할 수 없다.
컬렉션을 저장하기 위한 별도의 테이블이 필요하다.
@ElementCollection @CollectionTable(name = "FAVORITE_FOOD", joinColumns = @JoinColumn(name="MEMBER_ID") @Column(name = "FOOD_NAME") private Set<String> favoriteFoods = new HashSet<>(); @ElementCollection @CollectionTable(name = "addressHistory", joinColumns = @JoinColumn(name="MEMBER_ID") @Column(name = "ADDRESS") private List<Address> addressHistory = new ArrayList<>();
Java
복사
값 타입 컬렉션 사용
값 타입 조회 예제
값 타입 컬렉션도 지연 로딩 전략 사용
Member findMember = em.find(Member.class, 1L); /* SQL: select MEMBER_ID, street, zipcode, USERNAME from MEMBER where MEMBER_ID = 1L; */
Java
복사
값 타입 수정 예제
/*기본적인 임베디드 타입 변경*/ findMember.getHomeAddress().setCity("newCity");// 잘못된 수정 Address add = findMember.getHomeAddress(); findMember.setHomeAddress(new Address("newCity", add.getStreet(), add.getZipcode())); /*값 타입 컬렉션 수정 예제 - 치킨을 김밥으로 변경*/ findMember.getFavoriteFoods().remove("치킨"); findMember.getFavoriteFoods().add("김밥"); findMember.getAddressHistory().remove(new Address("old1", "street", "10000")); findMember.getAddressHistory().add(new Address("newCity", "street", "10000"));
Java
복사
값 타입 컬렉션들은 생명주기를 소유객체에 의존한다.
여기서 값 타입 컬렉션 실행 쿼리를 보면 기존 데이터만 삭제하고 신규 데이터를 추가하는 것이 아닌 값타입 컬렉션 데이터 전체가 갈아끼워진다.
참고: 값 타입 컬렉션은 영송석 전이(CASCADE)와 고아 객체 제거 기능을 필수로 가진다고 볼 수 있다.
값 타입 컬렉션의 제약사항
값 타입은 엔티티와 다르게 식별자 개념이 없다.
값은 변경하면 추적이 어렵다.
값 타입 컬렉션에서 변경 사항이 발생하면, 주인 엔티티와 연관된 모든 데이터를 삭제하고 값 타입 컬렉션에 있는 현재 값을 모두 다시 저장한다.
값 타입 컬렉션을 매핑하는 테이블은 모든 컬럼을 묶어서 기본키를 구성해야한다. (null 입력x, 중복 저장x)
이러한 이유로 실무에선 사용 안하는걸 추천한다.
실무에서는 상황에 따라 값 타입 컬렉션 대신 일대다 관계를 고려한다.
일대다 관계를 위한 엔티티를 만들고, 여기에서 값 타입을 사용
영속성 전이(CASCADE)+ 고아 객체 제거를 사용해서 값 타입 컬렉션처럼 사용
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "MEMBER_ID") private List<AddressEntity> addressHistory = new ArrayList<>();
Java
복사
값 타입 컬렉션 사용 시기
: 정말 단순한 경우 Ex: 좋아하는 음식메뉴 다중 선택과 같이 심플한 자료들.
정리
1.
엔티티 타입의 특징
식별자가 있다
생명 주기 관리(값 타입은 생명주기 관리를 주도적으로 할 수 없다.)
공유
2.
값 타입의특징
식별자가 없다
생명 주기를 엔티티에 의존
공유하지 않는 것이 안전(복사해서 사용)
불변 객체로 만드는 것이 안전

식별자가 필요하고, 값을 추적, 변경해야 한다면 그것은 값 타입이 아닌 엔티티

실전 예제 6 - 값 타입 매핑