Reference. 자바 ORM 표준 JPA 프로그래밍
책 목차 및 이전 글
더보기
들어가기 전 JPA 특징, Q&A
1. JPA 소개
3. 영속성 관리
4. 엔티티 매핑
4.1 - 4.3 @Entity, @Table, 다양한 매핑
4.4 - 4.5 데이터베이스 스키마 자동 생성, DDL 생성 기능
5. 연관관계 매핑 기초
6. 다양한 연관관계 매핑
7. 고급매핑
8. 프록시와 연관관계 관리
9. 값 타입
9.3~5 값 타입과 불변 객체, 값 비교, 값 타입 컬렉션
10. 객체지향 쿼리 언어
11. 웹 애플리케이션 제작
11.1 프로젝트 환경설정
11.2 도메인 모델과 테이블 설계
11.3 애플리케이션 구현
12. 스프링 데이터 JPA
12.1~3 스프링 데이터 JPA 소개, 공통 인터페이스 기능
12.5~10 명세, 사용자 정의 리포지토리, Web 확장...
13. 웹 애플리케이션과 영속성 관리
14.1 컬렉션
- JPA는 자바에서 기본으로 제공하는 Collection, List, Set, Map 컬렉션을 지원
- 컬렉션을 사용하는 상황 예시
- @OneToMany, @ManyToMany를 사용해서 일대다나 다대다 엔테티 관계를 매핑할 경우
- @ElementCollection을 사용해서 값 타입을 하나 이상 보관할 경우
- 자바 컬렉션 인터페이스의 특징들
Collection
: 자바가 제공하는 최상위 컬렉션, 하이버네이트는 중복을 허용하고 순서를 보장하지 않는다고 가정
Set
: 중복을 허용하지 않는 컬렉션, 순서를 보장하지 않음
List
: 순서가 있는 컬렉션, 순서를 보장하고 중복을 허용
Map
: Key, Value 구조로 되어 있는 특수한 컬렉션
14.1.1 JPA와 컬렉션
- 하이버네이트는 엔티티를 영속 상태로 만들 때 컬렉션 필드로 감싸서 사용
@Entity public class Team { @Id private String id; @OneToMany @JoinColumn private Collection<Member> members = new ArrayList<Member>(); ... }
//실행 코드 Team team = new Team(); System.out.println("before persist = "+ team.getMembers().getClass()); em.persist(team); System.out.println("after persist = " + team.getMebers().getClass()); //춮력 결과 before persist = class java.util.ArrayList after persist = class org.hibernate.collection.internal.PersistentBag
- 하이버네이트는 컬렉션을 효율적으로 관리하기 위해 엔티티를 영속 상태로 만들때 원본 컬렉션을 감싸고 있는 내장 컬렉션을 생성해서 내장 컬렉션을 사용하도록 참조를 변경
- 하이버네이트가 제공하는 내장 컬렉션은 원본 컬렉션을 감싸고 있어 래퍼 컬렉션이라고도 부름
- 하이버네이트는 이런 특징 떄문에 컬렉션을 사용할때 즉시 초기화를 권장
Collection<Member> members = new ArrayList<Member>();
- 인터페이스에 따른 래퍼 컬렉션 예시
//org.hibernate.collection.internal.PersistentBag @OneToMany Collection<Member> collection = new ArrayList<Member>(); //org.hibernate.collection.internal.PersistentBag @OneToMany List<Member> list = new ArrayList<Member>(); //org.hibernate.collection.internal.PersistentSet @OneToMany Set<Member> set = new HashSet<Member>(); //org.hibernate.collection.internal.PersistentList @OneToMany @OrderColumn List<Member> orderColumnList = new ArrayList<Member>();
하이버네이트 내장 컬렉션과 특징
컬렉션 인터페이스 내장 컬렉션 중복 허용 순서 보관 Collection, List PersistentBag O X Set PersistentSet X X List + @OrderColumn PersistentList O O
14.1.2 Collection, List
- Collection, List 인터페이스는 중복을 허용하고 PersistentBag 래퍼 컬렉션을 사용
- ArrayList로 초기화
//Entity ... @OneToMany @JoinColumn private Collection<CollectionChild> collection = new ArrayList<CollectionChild>(); @OneToMany @JoinColumn private List<ListChild> list = new ArrayList<ListChild>();
- 객체를 추가하는 add() 메소드는 항상 true 반환, 찾거나 삭제할 때는 equals() 메소드 사용
List<Comment> comments = new ArrayList<Comment>(); ... boolean result = comments.add(data); //단순 추가, 항상 true comments.contains(comment); //equals 비교 comments.remove(comment); //equals 비교
- Collection, List는 엔티티 추가할때 중복비교 없이 단순히 저장 따라서 엔티티를 추가해도 지연 로딩된 컬렉션을 초기화 X
14.1.3 Set
- Set은 중복을 허용하지 않는 컬렉션, PersistentSet을 컬렉션 래퍼로 사용
- HashSet으로 초기화
@Entity public class Parent { @OneToMany @JoinColumn private Set<SetChild> set = new HashSet<SetChild>(); ... }
- add() 메소드로 객체를 추가할 때 마다 equals() 메소드로 같은 객체가 있는지 비교
- 같은 객체가 없으면 객체를 추가하고 true 반환, 이미 있어서 실패하면 false를 반환
- 해시 알고리즘을 사용하므로 hashcode()도 함께 사용해서 비교
Set<Comment> comments = new HashSet<Comment>(); ... boolean result = comments.add(data); //hashcode + equals 비교 comments.contains(comment); //hashcode + equals 비교 comments.remove(comment); //hashcode + equals 비교
- Set은 추가할때 중복 엔티티를 비교, 따라서 엔티티를 추가할 때 지연 로딩된 컬렉션을 초기화
14.1.4 List + @OrderColumn
- List 인터페이스에 @OrderColumn을 추가하면 순서가 있는 특수한 컬렉션으로 인식
- 순서가 있다는 의미는 데이터베이스에 순서 값을 저장해서 조회할 때 사용한다는 의미
- 하이버네이트 내부 컬렉션인 PersistentList를 사용
@Entity public class Board { @Id @GeneratedValue private Long id; private String title; private String content; @OneToMany(mappedBy = "board") @OrderColumn(name = "POSITION") private List<Comment> comments = new ArrayList<Comment>() ... } @Entity public class Comment { @Id @GeneratedValue private Long id; private String comment; @ManyToOne @JoinColumn(name = "BOARD_ID") private Board board; ... } //사용 코드 list.add(1, data1); //1번 위치에 data1 저장 list.add(data1); list.get(10); //10번 위치에 있는 값 조회
- 순서가 있는 컬렉션은 데이터베이스에 순서 값도 함께 관리
@OrderColumn의 단점
- @OrderColumn을 Board 엔티티에 매핑하므로 Comment는 POSITION의 값을 알 수 없음 그래서 Board.comment의 위치 값을 사용해서 POSITION의 값을 UPDATE하는 SQL이 추가 발생
- List를 변경하면 연관된 많은 위치 값을 변경, 가운데 값을 줄이면 POSITION의 값을 각각 하나씩 줄이게 되므로 많은 UPDATE문이 발생
- POSITION 값이 없으면 조회한 List에는 null이 보관, 강제로 삭제 후 POSITION의 값을 수정하지 않으면 [0, 2, 3]이 되어 1값이 없는 현상 발생. 그로 인해 NullPointException이 발생
14.1.5 @OrderBy
- @OrderBy는 데이터베이스의 ORDER BY절을 사용해서 컬렉션을 정렬
- 순서용 컬럼을 매핑하지 않아도 가능
- @OrderBy는 모든 컬렉션에 사용 가능
@Entity
public class Team {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "team")
@OrderBy("username desc, id asc")
private Set<Member> members = new HashSet<Member>();
...
}
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
@Column(name = "MEMBER_NAME")
private String username;
@ManyToOne
private Team team;
...
}
- @OrderBy의 값은 JPQL의 order by절처럼 엔티티의 필드를 대상으로 적용
//초기화 Team findTeam = em.find(Team.class, team.getId()); findTeam.getMembers().size(); //초기화 //Team.members를 초기화 할 때 SQL 실행결과 SELECT M.* FROM MEMBER M WHERE M.TEAM_ID=? ORDER BY M.MEMBER_NAME DESC, M.ID ASC
'개발서적 > 자바 ORM 표준 JPA' 카테고리의 다른 글
[자바 ORM 표준 JPA 프로그래밍] 14.3 리스너 (0) | 2021.10.25 |
---|---|
[자바 ORM 표준 JPA 프로그래밍] 14.2 @Converter (0) | 2021.10.25 |
[자바 ORM 표준 JPA 프로그래밍] 13.4 너무 엄격한 계층 (0) | 2021.09.21 |
[자바 ORM 표준 JPA 프로그래밍] 13.3 OSIV (0) | 2021.09.21 |
[자바 ORM 표준 JPA 프로그래밍] 13.2 준영속 상태와 지연 로딩 (0) | 2021.09.21 |