# Chapter 14: 컬렉션과 부가 기능

<br>

## 1. 컬렉션

* JPA는 자바에서 기본으로 제공하는 Collection, List, Set, Map 컬렉션을 지원한다
* 사용하는 경우
  * `@OneToMany` `@ManyToMany` 를 사용해서 1:N이나 N:M 엔티티 관계를 매핑할 때
  * `@ElementCollection` 을 사용해서 값 타입을 하나 이상 보관할 때
* Map
  * Map은 복잡한 매핑에 비해 활용도가 떨어지고, 다른 컬렉션을 사용해도 충분함
  * Map은 `@MapKey*` 어노테이션으로 매핑할 수 있다

### 1-1. JPA와 컬렉션

* 하이버네이트는 엔티티를 영속 상태로 만들 때 컬렉션 필드를 하이버네이트에서 준비한 컬렉션으로 감싸서 사용한다
  * 하이버네이트는 컬렉션을 효율적으로 관리하기 위해 엔티티를 영속 상태로 만들 때, 원본 컬렉션을 감싸고 있는 `내장 컬렉션` 을 생성해서 내장 컬렉션을 사용하도록 참조를 변경한다
  * 하이버네이트가 제공하는 내장 컬렉션은 원본 컬렉션을 감싸고 있어서 `래퍼 컬렉션` 으로도 부른다
  * 이러한 특징 때문에 컬렉션을 사용할 때 `즉시 초기화`해서 사용하는 것을 권장한다

### 1-2. Collection, List

* Collection, List는 엔티티를 추가할 때 중복된 엔티티가 있는지 비교하지 않고 `단순히 저장`만 하면 된다
  * 따라서 엔티티를 추가해도 `지연 로딩` 된 컬렉션을 초기화 하지 않는다

### 1-3. Set

* Set은 엔티티를 추가할 때 `중복된 엔티티` 가 있는지 `비교` 해야한다
* 따라서 엔티티를 추가할 때 `지연 로딩` 된 컬렉션을 `초기화` 한다

### 1-4. List + @OrderColum

* List 인터페이스에 `@OrderColumn` 을 추가하면 `순서가 있는` 특수한 컬렉션으로 인식한다
  * 순서가 있다는 의미는 DB에 순서 값을 저장해서 조회할 때 사용한다는 의미다
  * 순서가 있는 컬렉션은 DB에 순서 값도 함께 관리한다
* `@OrderColumn` 의 단점
  * INSERT 시 순서 값 필드를 UPDATE 하는 SQL이 추가로 발생한다
  * List를 변경하면 연관된 많은 위치 값을 변경해야 한다
  * 중간에 순서 값 필드에 값이 없으면 조회한 List에는 null이 보관되므로, 조회 시 컬렉션을 순회할때 NullPointerException이 발생한다

### 1-5. @OrderBy

하이버네이트는 Set에 @OrderBy를 적용해서 조회하면, 순서를 유지하기 위해 HashSet 대신에 LinkedHashSet을 내부에서 사용한다

## 2. @Converter

* 컨버터를 사용하면 엔티티의 데이터를 변환해서 DB에 저장할 수 있다
* 글로벌 설정을 하면 @Converter를 지정하지 않아도 모든 타입에 대해 자동으로 컨버터가 적용된다

## 3. 리스너

→ entity 생명 주기…! pre*post*

JPA 리스너 기능을 사용하면 엔티티의 `생명 주기`에 따른 이벤트를 처리할 수 있다

### 이벤트 적용 위치

* 엔티티에 직접 적용
* 별도의 리스너 등록 → `@EntityListeners`
* 기본 리스너 사용

### 여러 리스너를 등록했을 때, 이벤트 호출 순서

1. 기본 리스너
2. 부모 클래스 리스너
3. 리스너
4. 엔티티

## 4. 엔티티 그래프

엔티티 그래프 기능은 `엔티티 조회 시점` 에 연관된 엔티티들을 `함께 조회`하는 기능

* `@NamedEntityGraph` 사용
* JPQL에서 엔티티 그래프를 사용할 때는 em.find() 와 동일하게 힌트만 추가
  * ex) .setHint()
* 동적으로 엔티티 그래프를 구성하려면 `em.createEntityGraph()` method 사용

### 엔티티 그래프 특징

* ROOT에서 시작
  * 엔티티 그래프는 항상 조회하는 엔티티의 ROOT에서 시작해야 한다
* 이미 로딩된 엔티티
  * 영속성 컨텍스트에 해당 엔티티가 이미 로딩되어 있으면 그래프가 적용되지 않는다
    * 아직 초기화되지 않은 프록시에는 엔티티 그래프가 적용된다
* `fetchgraph`, `loadgraph`의 차이
  * fetchgraph
    * 엔티티 그래프에 선택한 속성만 함께 조회
  * loadgraph
    * 엔티티 그래프에 선택한 속성뿐만 아니라 글로벌 fetch 모드가 `FetchType.EAGER` 로 설정된 연관관계도 포함해서 함께 조회

## 5. 정리

* JPA가 지원하는 `컬렉션` 종류와 특징
* `컨버터`를 사용하면 엔티티의 데이터를 `변환` 해서 DB에 저장할 수 있다
* `리스너`를 사용하면 엔티티에서 발생한 `이벤트를 받아서 처리`할 수 있다
* FETCH JOIN은 객체지향 쿼리를 사용해야 하지만, `엔티티 그래프`를 사용하면 객체 지향 쿼리를 사용하지 않아도 원하는 객체 그래프를 `한 번에 조회`할 수 있다
