tonykang22 / study

0 stars 0 forks source link

[JPA] 14장. 컬렉션과 부가기능 #159

Open leeyuunsung opened 1 year ago

leeyuunsung commented 1 year ago

14장. 컬렉션과 부가기능

14.1 컬렉션

14.1.1 JPA와 컬렉션

14.1.2 Collection, List

14.1.3 Set

14.1.4 List + @OrderColumn

@OrderColumn의 단점 (→ 실무에 잘 사용X)

14.1.5 @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>();
        ...
}

14.2 @Converter

// VIP를 Y와N으로 지정하고 싶은 경우
@Entity
public class Member {
        @Id
        private String id;
        private String username;

        @Convert(converter=BooleanToYNConverter.class)
        private boolean vip;

        //Getter, Setter
        ...
}

14.2.1 글로벌 설정

14.3 리스너

14.3.1 이벤트 종류

  1. PostLoad
    • 엔티티가 영속성 컨텍스트에 조회된 직후 또는 refresh를 호출한 후
  2. PrePersist
    • persist() 메소드를 호출해서 엔티티를 영속성 컨텍스트에 관리하기 직전에 호출
  3. PreUpdate
    • flush나 commit을 호출해서 엔티티를 DB에 수정하기 직전에 호출
  4. PreRemove
    • remove() 를 호출해서 엔티티를 영속성 컨텍스트에서 삭제하기 직전에 호출
    • 삭제 명령어로 영속성 전이가 일어날때도 호출
  5. PostPersist
    • flush나 commit을 호출해서 엔티티를 DB에 저장한 직후에 호출
    • 식별자가 항상 존재. 식별자 생성 전략이 IDENTITY면 식별자 생성을 위해 persist()를 호출하면서 DB에 엔티티를 저장하므로 이때는 persist()를 호출한 직후에 PostPersist 호출
  6. PostUpdate
    • flush나 commit을 호출해서 엔티티를 DB에 수정한 직후에 호출
  7. PostRemove
    • flush나 commit을 호출해서 엔티티를 DB에 삭제한 직후에 호출

14.3.2 이벤트 적용 위치

엔티티에 직접 적용

@Entity
public class Duck {

        @Id @GeneratedValue
        public Long id;

        private String name;

        @PrePersist
        public void prePersist() {
                System.out.println("Duck.prePersist id=" + id);
        }

        @PostPersist
        public void postPersist() {
                System.out.println("Duck.postPersist id=" + id);
        }

        @PostLoad
        public void postLoad() {
                System.out.println("Duck.postLoad");
        }

        @PreRemove
        public void preRemove() {
                System.out.println("Duck.preRemove");
        }

        @PostRemove
        public void postRemove() {
                System.out.println("Duck.postRemove");
        }
}

별도의 리스너 등록

@Entity
**@EntityListeners(DuckListener.class)**
public class Duck {
        ...
}

public class DuckListener {
        @PrePersist
        //특정 타입이 확실하면 특정 타입을 받을 수 있다.
        private void prePersist(Object obj) {
                System.out.println("DuckListener.prePersist obj = [" + obj + "]");
        }

        @PostPersist
        //특정 타입이 확실하면 특정 타입을 받을 수 있다.
        private void postPersist(Object obj) {
                System.out.println("DuckListener.postPersist obj = [" + obj + "]");
        }
}

기본 리스너 사용

더 세밀한 설정

14.4 엔티티 그래프

// case 1
select o from Order o
    where o.status = ?

// case 2
select o from Order o
    join fetch o.member 
    where o.status = ?

// case 3
select o from Order o
    join fetch o.orderItems
    where o.status = ?

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;

        // 지연로딩 설정이나 엔티티 그래프 설정으로 Order를 조회할 때 연관된 member도 함께 조회 가능
        @ManyToOne(fetch = FetchType.LAZY, optional = false)
        @JoinColumn(name = "MEMBER_ID")
        private Member member;

        ...
}

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);

14.4.3 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; //주문 상품

        ...
}

14.4.4 JPQL에서 엔티티 그래프 사용

14.4.5 동적 엔티티 그래프

14.4.6 엔티티 그래프 정리