값 타입 컬렉션
Last updated
Last updated
값 타입의 컬렉션을 갖는 Member 객체
MEMBER_ID와 값타입의 필드를 모두 묶어서 하나 PK로 한다! MEMBER_ID는 PK이면서 동시에 FK이다.(이후에 나올 Side-Effect의 원인)
값 타입 컬렉션을 별도의 테이블로 생성해서 MEMBER와 일대다 관계로 매핑한다! =>그렇기 때문에 DB는 각각의 컬렉션들을 같은 테이블에 저장할 수 없다!
값 타입 컬렉션을 DB에 저장하는 방법
위의 내용처럼 값 타입 컬렉션 각각은 모두 별도의 테이블로 생성된다. 그러면 지금까지 테이블에 데이터를 저장한 방법을 생각해보면 각각의 컬렉션 테이블에 데이터를 넣고 persist를 해주어야할 것 같다! 그런데 MEMBER에 매핑해주고 MEMBER의 필드(컬럼)인 값 타입 컬렉션에 데이터를 넣어주면 해당 컬렉션 테이블에도 자동으로 데이터가 저장되는 것을 알 수 있다!
값 타입 컬렉션들은 MEMBER에 소속되어 라이프사이클 또한 따라간다. (MEMBER에 의존하고, 종속적이다.) 그렇기 때문에 값 타입 컬렉션의 테이블에 별도로 persist를 하지 않아도 MEMBER 테이블의 데이터 수정에 따라 함께수정된다!
Member 객체에 속한 다른 필드들처럼 값 타입 컬렉션들도 "값 타입(기본값, 임베디드 값, 컬렉션 값)"이다!
cascadetype=ALL, orphanRemoval=true 를 적용한 것과 비슷하다.
2. 값 타입 조회
Member를 조회해보면 값 타입 컬렉션들은 제외하고 멤버에 소속된 값 타입 데이터들만 조회되는 것을 알 수 있다! fetchType = LAZY와 같다!
@ElementCollection의 디폴트 fetch 타입은 LAZY인 것을 확인할 수 있다!
값 타입을 저, 조회하는 것만 보면 정말 좋다고 느껴지지만 수정부분을 보자!
3. 값 타입 수정
Member의 값 타입인 homeAddress를 수정하고 싶을 때 아래처럼 해도 될 것 같지만, 값 타입은 한 객체에서 인스턴스를 수정하면 공유하고 있는 객체들도 모두 수정되는 Side-Effect 때문에 emmutable 해야하기 때문에 아래 코드처럼 하면 안 된다!(Setter 사용 금지❌) 값 타입은 객체를 새로 생성해서 새로 값을 넣어주어야 한다!!!
컬렉션 값을 수정할 때는 기존 객체를 삭제하고 새로 생성해야한다. 대부분의 컬렉션들은 어떤 대상을 찾을 때 기본적으로 equals를 사용한다. 그렇기 때문에 equals와 hashCode를 제대로 오버라이딩하지 않으면 값이 계속 들어간다.
Collections.remove()로 객체 인스턴스를 조회해서 지운다!
조회한 MEMBER_ID의 address 데이터를 지운다!
값을 하나 삭제하고 다른 데이터를 새로 넣으면 INSET문이 한번이 아니라 2번 나오는 것을 확인할 수 있다! 기존의 데이터와 새로 넣는 데이터 모두 새롭게 INSERT 된 것이다.
값 타입 컬렉션의 제약사항
값 타입은 엔티티와 다르게 식별자 개념이 없기 때문에 한번 변경하면 추적이 어렵다. =>@OrderColumn을 사용하면 가능하기도 하지만 원하는 대로 동작하지 않는다고 함.
값 타입 컬렉션에 변경 사항이 발생하면, 주인 엔티티와 연관된 모든 데이터를 삭제하고, 값 타입 컬렉션에 있는 현재 값을 모두 다시 저장한다.⭐️⭐️⭐️⭐️⭐️
값 타입 컬렉션을 매핑하는 테이블은 모든 컬럼을 묶어서 PK를 구성하기 때문에 null 입력❌, 중복 저장❌
값 타입을 엔티티로 바꾼다!(승격한다)
실무에서는 상황에 따라 값 타입 컬렉션 대신에 일대다 관계를 고려
일대다 관계를 위한 엔티티를 만들고, 여기에서 값 타입을 사용 일 : Member 다 : 값타입=>엔티티 일대다 중 일 쪽(MEMBER)가 FK로 <AddressEntity> List 컬렉션을 수정하면 UPDATE 쿼리가 2번 발생한다! 일(TEAM) 에 FK가 있을 때는 TEAM의 필드 FK만 수정되는 것이 아니라 다(MEMBER) 도 수정되기 때문이다!)
=>MEMBER의 FK인 List<AddrressEntity>만 수정되는 것이 아니라 매핑 상대인 AddressEntity도 수정된다!!! (일대다 단방향 관계에서
영속성 전이(Cascade) + 고아 객체 제거 사용 => 값 타입 컬렉션 처럼 사용(라이프사이클 동일하게)
값 타입 컬렉션을 엔티티로 생성하고 DB를 확인해보면 ADDRESS 테이블 <- ID 생기고, MEMBER_ID는 FK 로 갖는다. =>자체적인 ID가 생겼는 것은 값타입이 아니라 엔티티라는 것을 의미한다!