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. 컬렉션과 부가기능
- 엔티티 조회시 연관된 엔티티를 함께 조회하려면 글로벌 fetch 옵션을
FetchType.EAGER
로 설정@Entity class Order { @ManyToOne(fetch=FetchType.EAGER) Member member; ... }
- 또는 JPQL에서 페치 조인을 사용
select o from Order o join fetch o.member
- 글로벌 옵션은 전체 영향을 주는 단점,
FetchType.LAZY
를 쓰고 필요할때 JPQL 페치조인 사용
- JPQL이 데이터 조회뿐아니라 연관 엔티티를 함께 조회하는 기능도 제공하기 때문에 JPQL을 중복해서 많이 사용, 연관된 엔티티를 함께 조회하는 기능은 엔티티 그래프 사용 권장
- 엔티티 그래프 기능은 엔티티 조회시점에 연관된 엔티티들을 함께 조회하는 기능
14.4.1 Named 엔티티 그래프
- 주문(Order)을 조회할 때 연관된 회원(Member)도 함께 조회하는 엔티티 그래프 예시
@NamedEntityGraph(name = "Order.withMember", attributeNodes = { @NamedAttributeNode("member") }) @Entity @Table(name = "ORDERS") public class Order { @Id @GeneratedValue @Column(name = "ORDER_ID") private Long id; @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "MEMBER_ID") private Member member; ... }
- Named 엔티티 그래프는
@NamedEntityGraph
로 정의- name: 엔티티 그래프의 이름을 정의
- attributeNodes: 함께 조회할 속성 선택
@NamedAttributeNode
를 사용하고 그 값으로 함께 조회할 속성을 선택
- 지연로딩 설정이지만 엔티티 그래프 설정으로 Order를 조회할 때 member도 함께 조회 가능
- 둘 이상 정의하려면
NamedEntityGraphs
를 사용
14.4.2 em.find()에서 엔티티 그래프 사용
- 엔티티 그래프 사용 예시
EntityGraph graph = em.getEntityGraph("Order.withMember"); Map hints = new HashMap(); hints.put("javax.persistence.fetchgraph", graph); Order order = em.find(Order.class, orderId, hints);
- Named 엔티티 그래프를 사용하려면
em.getEntityGraph("Order.withMember")
를 사용
- JPA의 힌트 기능을 사용해서 동작, 힌트 키는
javax.persistence.fetchgraph
사용//실행된 SQL select o.*, m.* from ORDERS o inner join Member m on o.MEMBER_ID = m.MEMBER_ID where o.ORDER_ID = ?
14.4.3 subgraph
- Order → OrderItem → Item까지 조회하는 경우 subgraph를 사용
- subgraph 예시
@NameEntityGraph(name = "Order.withAll", attributeNodes = { @NameAttributeNode("member"), @NameAttributeNode(value = "orderItems", subgraph = "orderItems") }, subgraphs = @NamedSubgraph(name = "orderItems", attributeNodes = { @NameAttributeNode("item") }) ) @Entity @Table(name ="ORDERS") public class Order { @Id @GeneratedValue @Column(name = "ORDER_ID") private Long id; @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "MEMBER_ID") private Member member; //주문 회원 @OneToMany(mappedBy = "order", cascade = CascadeType.ALL) private List<OrderItem> orderItems = new ArrayList<OrderItem>(); ... } @Entity @Table(name = "ORDER_ITEM") public class OrderItem { @Id @GeneratedValue @Column(name = "ORDER_ITEM_ID") private Long id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "ITEM_ID") private Item item; //주문 상품 ... }
- OrderItem → Item은 Order의 객체 그래프가 아니므로 subgraphs 속성 정의가 필요
- @NamedSubgraph를 사용해서 서브 그래프를 정의
- 사용하는 코드 예시
Map hints = new HashMap(); hints.put("javax.persistence.fetchgraph", em.getEntityGraph("order.withAll")); Order order = em.find(Order.class, orderId, hints);
select o.*, m.*, oi.*, i.* from ORDERS o inner join Member m on o.MEMBER_ID = m.MEMBER_ID left outer join ORDER_ITEM oi on o.ORDER_ID = oi.ORDER_ID left outer join Item i on oi.ITEM_ID = i.ITEM_ID where o.ORDER_ID = ?
14.4.4 JPQL에서 엔티티 그래프 사용
- em.find()와 동일하게 힌트만 추가하면 사용 가능
List<Order> resultList = em.createQuery("select o from Order o where o.id = :orderId", Order.class) .setParameter("orderId", orderId) .setHint("javax.persistence.fetchgraph", em.getEntityGraph("Order.withAll")) .getResultList();
select o.*, m.*, oi.*, i.* from ORDERS o left join Member m on o.MEMBER_ID = m.MEMBER_ID left outer join ORDER_ITEM oi on o.ORDER_ID = oi.ORDER_ID left outer join Item i on oi.ITEM_ID = i.ITEM_ID where o.ORDER_ID = ?
em.find()
에서 필수 관계(optional = false
)를 고려해서 내부 조인을 사용하지만 JPQL에서 엔티티 그래프를 사용할 때는 항상 SQL 외부 조인을 사용
- SQL 내부 조인을 사용하려면 내부 조인 명시가 필요
select o from Order o join fetch o.member where o.id = :orderId
14.4.5 동적 엔티티 그래프
- 엔티티 그래프를 동적으로 구성하려면 createEntityGraph() 메소드를 사용
public <T> EntityGraph<T> createEntityGraph(Class<T> rootType);
- 처음에 사용한 Named 엔티티 그래프 동적으로 재구성 예시
EntityGraph<Order> graph = em.createEntityGraph(Order.class); graph.addAttributeNodes("member"); Map hints = new HashMap() hints.get("javax.persistence.fetchgraph", graph); Order order = em.find(Order.class, orderId, hints);
- 동적 엔티티 그래프 subgraph 예시
EntityGraph<Order> graph = em.createEntityGraph(Order.class); graph.addAttributeNodes("member"); Subgraph<OrderItem> orderItems = graph.addSubgraph("orderItems"); orderItems.addAttributeNodes("item"); Map hints = new HashMap() hints.get("javax.persistence.fetchgraph", graph); Order order = em.find(Order.class, orderId, hints);
14.4.6 엔티티 그래프 정리
- ROOT에서 시작
- 엔티티 그래프는 항상 조회하는 엔티티의 ROOT에서 시작
- 이미 로딩된 엔티티
- 영속성 컨텍스트에 엔티티가 이미 로딩되어 있으면 엔티티 그래프 적용 X
Order order1 = em.find(Order.class, orderId); //이미 조회 hints.put("javax.persistence.fetchgraph", em.getEntityGraph("Order.withMember")); Order order2 = em.find(Order.class, orderId, hints); //엔티티 그래프 적용 X
- 영속성 컨텍스트에 엔티티가 이미 로딩되어 있으면 엔티티 그래프 적용 X
- fetchgraph, loadgraph의 차이
fetchgraph
는 엔티티 그래프에 선택한 속성만 함께 조회
loadgraph
는 선택한 속성 + FetchType.EAGER로 설정된 연관관계도 함께 조회
'개발서적 > 자바 ORM 표준 JPA' 카테고리의 다른 글
[자바 ORM 표준 JPA 프로그래밍] 15.2 엔티티 비교 (0) | 2021.10.25 |
---|---|
[자바 ORM 표준 JPA 프로그래밍] 15.1 예외 처리 (0) | 2021.10.25 |
[자바 ORM 표준 JPA 프로그래밍] 14.3 리스너 (0) | 2021.10.25 |
[자바 ORM 표준 JPA 프로그래밍] 14.2 @Converter (0) | 2021.10.25 |
[자바 ORM 표준 JPA 프로그래밍] 14.1 컬렉션 (0) | 2021.10.25 |