JPA는 자바에서 기본으로 제공하는 Collection, List, Set, Map 컬렉션을 지원하고, 아래와 같은 상황에서 컬렉션을 사용할 수 있다.
@OneToMany, @ManyToMany 를 사용해서 일대다나 다대다 관계를 매핑할 때
@ElementCollection 을 사용해서 값 타입을 하나 이상 보관할 때
하이버네이트는 엔티티를 영속상태로 만들 때 컬렉션 필드를 하이버네이트에서 준비한 컬렉션으로 감싸서 사용한다.
이는 하이버네이트가 컬렉션을 효율적으로 관기하기 위함이다.
하이버네이트는 본 컬렉션을 감싸고 있는 내장 컬렉션을 생성한 뒤, 이 내장 컬렉션을 사용하도록 참조를 변경한다.
Collection, List
중복을 허용하는 컬렉션이다.
하이버네이트에서 PersistentBag으로 래핑된다. 사용할 때는 ArrayList로 초기화하면 된다.
@OneToMany(mappedBy = "parent")
Collection<Child> children = new ArrayList<>();
// or
@OneToMany(mappedBy = "parent")
List<Child> children = new ArrayList<>();
중복을 허용하는 특성때문에 겍체를 추가할때 아무 조건검사가 필요없으므로, 지연로딩이 발생하지 않는다.
하지만 엔티티가 있는지 체크하거나 삭제할 경우 eqauls로 비교해야 하므로 지연로딩이 발생한다.
children.add(child); // no action
children.contains(child); // Lazy loading occurs because of using equals
children.remove(child); // Lazy loading occurs because of using equals
Set
중복을 허용하지 않는 컬렉션이다.
하이버네이트에서 PersistentSet으로 래핑된다. 사용할 때는 HashSet으로 초기화하면 된다.
@OneToMany(mappedBy = "parent")
Set<Child> children = new HashSet<>();
중복을 허용하지 않으므로 객체를 추가할 때 마다 equals 메서드로 같은 객체가 있는지 비교한다. 즉 add 메서드만 수행해도 지연로딩이 발생한다.
참고로 HashSet은 해시 알고리즘을 사용하므로 equals와 hashCode를 같이 사용한다.
컬렉션
JPA는 자바에서 기본으로 제공하는 Collection, List, Set, Map 컬렉션을 지원하고, 아래와 같은 상황에서 컬렉션을 사용할 수 있다.
하이버네이트는 엔티티를 영속상태로 만들 때 컬렉션 필드를
하이버네이트에서 준비한 컬렉션
으로 감싸서 사용한다.이는 하이버네이트가 컬렉션을 효율적으로 관기하기 위함이다.
하이버네이트는 본 컬렉션을 감싸고 있는 내장 컬렉션을 생성한 뒤, 이 내장 컬렉션을 사용하도록 참조를 변경한다.
Collection, List
중복을 허용하는 컬렉션이다.
하이버네이트에서
PersistentBag
으로 래핑된다. 사용할 때는ArrayList
로 초기화하면 된다.중복을 허용하는 특성때문에 겍체를 추가할때 아무 조건검사가 필요없으므로, 지연로딩이 발생하지 않는다.
하지만 엔티티가 있는지 체크하거나 삭제할 경우 eqauls로 비교해야 하므로 지연로딩이 발생한다.
Set
중복을 허용하지 않는 컬렉션이다.
하이버네이트에서
PersistentSet
으로 래핑된다. 사용할 때는HashSet
으로 초기화하면 된다.중복을 허용하지 않으므로 객체를 추가할 때 마다 equals 메서드로 같은 객체가 있는지 비교한다. 즉 add 메서드만 수행해도 지연로딩이 발생한다.
참고로 HashSet은 해시 알고리즘을 사용하므로 equals와 hashCode를 같이 사용한다.
List + @OrderColumn
순서가 있는 복수형 컬렉션을 의미하는데, 데이터베이스에 순서값을 저장해서 조회할 때 사용한다는 의미이다.
위처럼 데이터베이스에 순서값을 함꼐 관리하는 테이블에 사용된다.
List의 위치(순서)값을
POSITION
이라는 컬럼에 저장하게 되는것이고, 이는 일대다 관계의 특성에 따라 다(N)쪽에 저장하게 된다.아래는 사용예제이다.
어떻게보면 위치값을 알아서 관리해주니 편해보이지만 사실은 실무에서 사용하기에는 단점이 많다.
이러한 특징때문에 위의 명령을 수행하면 comment1, comment2 insert 후에 POSITION 값을 수정하는 update가 2번 추가로 발생한다(ㄷㄷ)
컨버터
@Converter
를 사용하면 엔티티의 데이터를 변환해서 데이터베이스에 저장할 수 있다.예를 들면 엔티티에는 boolean, 데이터베이스에는 YN 값을 저장하고 싶을 경우 정도가 있겠다.
(기본적으로 boolean 타입으로 지정하면 0,1로 저장된다)
기본 사용법
보다시피 간단하다.
AttributeConverter
를 구현하면서 제네릭으로엔티티 컬럼 타입, 데이터베이스 컬럼 타입
을 주고,아래 2개의 메서드를 오버라이드 해주면 된다(엔티티->데이터베이스, 데이터베이스->엔티티)
클래스 레벨 설정
클래스 레벨에도 설정할 수 있다. 단 이때는 attrbuteName 속성을 사용해서 어떤 필드에 컨버터를 적용할 지 명시해야한다.
글로벌 설정
모든 Boolean 타입에 설정하고 싶을 경우 아래와 같이 직접 컨버터에 명시해주면 된다.
이렿게 하면 엔티티에 따로 컨버터를 지정해주지 안항도 자동으로 컨버팅 된다.