14장 컬렉션과 부가 기능
컬렉션
JPA 는 Collection, Map, Set, List 등 의 컬렉션을 지원한다. 그리고 다음과 같은 경우에 컬렉션을 사용할수있다.
@OneToMany, @ManyToMany 를 사용해서 1:N, N:N 관계를 매핑할때
@ElementCollection 을 사용해서 값 타입을 하나 이상 보관할때
자바 컬렉션 특징
Collection : 자바가 제공하는 최상위 컬렉션
Map : key : value 값으로 되어있고 Key는 중복이 없어야 하지만 value는 중복가능
Set : 중복 허용 x, 순서 보장 x
List : 중복 허용 o, 순서보장 o
래퍼 컬렉션
하이버네이트는 엔티티를 영속상태로 만들 때 컬렉션 필드를 하이버네이트 에서 준비한 컬렉션으로 감싸서 사용한다. 원본 컬렉션을 감싸고 있는 내장 컬렉션을 생성해서 내장 컬렉션을 사용하도록 참조를 변경한다. 그래서 원본을 내장 컬렉션이 감싸고있어서 래퍼 컬렉션이라고도 부른다.
Collection, List
이 둘은 엔티티를 추가 할때 따로 중복검사를 진행하지 않고 저장된다. 엔티티 추가 시 지연로딩 컬렉션 초기화도 하지 않는다.
Set
add() 메서드로 객체를 추가할 때 마다 equals() 메서드로 동일한 객체가 있는지 비교함. 없으면 true
있으면 false를 반환한다. HashSet은 해시 알고리즘을 사용하여 hascode() 도 함께 사용해서 비교함
List + @OrderColumn
List 에다 @OrderColumn 을 추가 한다면 순서가 있는 컬렉션으로 인식한다.
기본 컬럼 외에 새로운 컬럼에 순서값을 저장해서 그것으로 조회한다.
단점
주인 엔티티는 postion 값을 모르기때문에 INSERT 시 Position 값이 저장이 안되서 해당 position을 조회해서 업데이트 하는 쿼리가 한번 더 날라감
List 가 변경되면 바꿔야 하는 부분이 너무 많다. position 1번이 빠지면 모든 position이 하나씩 줄어들어야 하기 때문에 UPDATE SQL 을 몇번이나 날려야 한다.
중간에 POSITION 값이 없으면 List 에 NULL 이 보관되고 해당 부분을 삭제하거나 수정하지 않으면 순회할때 NullPointerException 발생한다.
@OrderBy
OrderBy 는 DB 의 ORDER BY 절을 사용해서 컬렉션을 정렬한다. 그렇기에 List 뿐 아니라 다른 모든 컬렉션에 사용할수있다.
@Converter
엔티티의 데이터를 변환해서 DB 에 저장 할 수 있다.
convertToDatabaseColumn()
엔티티의 데이터를 DB 컬럼에 저장할 데이터로 변환한다.
convertToEntityAttribute()
DB 에서 조회한 데이터를 엔티티 데이터로 변환한다.
컨버터는 컬럼 레벨 에서 뿐 아니라 클래스 레벨 에서도 선언할 수 있다.
또한 글로벌 설정도 가능하여서 모든 Boolean 타입에 컨버터를 적용할수있다.
@Converter(autoApply = true)



로컬에서 실행해보니 false = NO, true = YES 로 잘 저장 되었다.

다시 DB에서 불러낼때도 false 값으로 잘 나온다.
리스너
엔티티의 생명주기에 따른 이벤트를 처리할 수 있다.
PostLoad : 엔티티가 영속성 컨텍스트에 조회된 직후 또는 refresh 를 호출한 후 시점에 호출
PrePersist : 엔티티가 persist() 메서드에 호출 되어 영속성 컨텍스트의 관리를 받기 직전 시점에 호출
PreUpdate : 엔티티가 업데이트 직전 commit, flush 하기 직전 시점에 호출
PreRemove : remove() 메서드 호출해서 엔티티를 영속성 컨텍스트에서 삭제 하기 직전 시점에 호출또한 삭제 명렁어로 영속성 전이가 일어날 때도 호출된다. orphanremoval 에서는 flush. commit 시에 호출 된다.
PostPersist : flush. commit 을 호출한 후 엔티티가 DB에 저장 된 직후 호출된다. 하지만 만약 식별자 생성 전략이 IDENTITY 면 식별자(ID값)를 생성하기 위해 persist() 를 호출하면서 DB에 엔티티를 저장한다. 이때는 persist()를 호출한 직후가 호출 시점이 된다.
PostUpdate : flush. commit 호출해서 엔티티를 DB에서 수정한 직후에 호출된다.
PostRemove : flush. commit 을 호출해서 엔티티를 DB에서 삭제한 직후에 호출된다.
이벤트 적용 위치
엔티티에 직접 적용
별도의 리스너를 작성해서 사용
리스너 클래스를 만들어서 여러개 리스너 메서드를 조합해서 원하는 엔티티에 선언해주면 된다.
기본 리스너를 사용
모든 엔티티에 적용되는 방식이다. xml 형태로 META-INF/orm.xml 에 작성해주면 된다.
아래에 어노테이션으로 더 세밀하게 설정할수있다.
@ExcludeDefaultListeners : 기본 리스너 무시
@ExcludeSuperclassListeners : 상위 클래스 이벤트 리스너 무시
엔티티 그래프 (Entity Graph)
JPA에서 제공하는 페치조인을 좀 더 편하게 사용할수있는 기능이다.
사용 방법
Repository 단에 어노테이션으로 작성

해당 Member 엔티티는 Board(게시판) 와 연관관계에 놓여있다.
findAll 을 통해 모든 멤버들을 리스트로 찾고 해당 멤버들이 작성한 게시글 까지 불러온다.
어노테이션을 통해 선언해주고 attributePaths 옵션에 연관관계에 놓인 불러올 엔티티를 적어주었다.''
+ 아래 처럼 @Query 를 같이 사용해도 된다.

Before
After
Last updated