Specification<MemberData> spec =SpecBuilder.builder(MemberData.class).ifTrue(searchRequest.isOnlyNotBlocked(), () ->MemberDataSpecs.nonBlocked()).ifHasText(searchRequest.getName(), name ->MemberDataSpecs.nameLike(searchRequest.getName())).toSpec();List<MemberData> result =memberDataDao.findAll(spec,PageRequest.of(0,5));
새로 추가한 밸류 타입을 알맞는 형식으로 출력하지 못하므로 값을 기본 타입으로 변환하면 편리
publicinterfaceOrderSummaryDaoextendsRepository<OrderSummary,String> { @Query(""" select new com.myshop.order.query.dto.OrderView( o.number, o.state, m.name, m.id, p.name ) from Order o join o.orderLines ol, Member m, Product p where o.orderer.memberId.id = :ordererId and o.orderer.memberId.id = m.id and index(ol) = 0 and ol.productId.id = p.id order by o.number.number desc """)List<OrderView> findOrderView(String ordererId);}...publicclassOrderView {privatefinalString number;privatefinalOrderState state;privatefinalString memberName;privatefinalString memberId;privatefinalString productName;publicOrderView(OrderNo number,OrderState state,String memberName,MemberId memberId,String productName) {this.number=number.getNumber();this.state= state;this.memberName= memberName;this.memberId=memberId.getId();this.productName= productName; }...}
동적 인스턴스의 장점은 JPQL을 그대로 사용하므로 객체 기준으로 쿼리를 작성하면서도 동시에 지연/즉시 로딩과 같은 고민 없이 원하는 모습으로 데이터를 조회할 수 있다는 점이다.
하이버네이트 @Subselect 사용
하이버네이트는 JPA 확장 기능으로 @Subselect를 제공`
쿼리 결과를 @Entity로 매핑할 수 있는 유용한 기능
@Entity@Immutable@Subselect(""" select o.order_number as number, o.version, o.orderer_id, o.orderer_name, o.total_amounts, o.receiver_name, o.state, o.order_date, p.product_id, p.name as product_name from purchase_order o inner join order_line ol on o.order_number = ol.order_number cross join product p where ol.line_idx = 0 and ol.product_id = p.product_id""")@Synchronize({"purchase_order","order_line","product"})publicclassOrderSummary { @IdprivateString number;privatelong version; @Column(name ="orderer_id")privateString ordererId; @Column(name ="orderer_name")privateString ordererName;...
@Immutable, @Subselect, @Synchronize는 하이버네이트 전용 애노테이션인데, 이 태그로 테이블이 아닌 쿼리 결과를 @Entity로 매핑 가능하다.
@Subselect
조회 쿼리를 값으로 갖는다.
select 쿼리 결과를 매핑할 테이블처럼 사용(DBMS의 뷰와 유사)
뷰와 동일하게 @Subselect로 조회한 @Entity는 수정 불가
@Immutable
@Subselect를 이용한 @Entity의 매핑 필드 수정 시 하이버네이트가 변경 내역을 반영하여 update 쿼리를 실행하는 문제를 방지하기 위해 사용
매핑 테이블이 없으므로 에러가 발생하는데 이 문제를 방지
@Immutable를 사용하면 해당 엔티티의 매핑 필드/프로퍼티가 변경되어도 DB에 반영하지 않고 무시
@Synchronize
엔티티 상태 변경 내역이 아직 테이블이 반영되지 않은 상태(커밋 전 시점)에서 조회 시 최신 값이 아닌 이전 값이 담기는 문제를 해소하기 위해 사용
해당 엔티티와 관련된 테이블 목록 명시
하이버네이트는 엔티티 로딩 전에 지정한 테이블과 관련된 변경이 발생하면 flush 수행
.
@Subselect를 사용해도 일반 @Entity와 같으므로 EntityManager#find(), JPQL, Criteria, Spec을 사용한 조회가 가능