[07] Querydsl

Veloger·2022년 12월 13일
0

ShopWeb_Project

목록 보기
7/7
  • @Query는 JPQL 문법을 문자열로 입력하기 때문에, 컴파일 시점에 에러가 발견되지 않는다.
  • 이를 보완하기 위한 Querydsl를 알아보자.

Querydsl

@Query("select i from Item wheere ...)

위 코드의 JPQL의 문법 중 where를 wheere로 잘못 입력되었다.
이때 Querydsl이 오타 발생시 바로 알려주고, 동적으로 쿼리를 생성해준다!

Querydsl 장점

  • 고정된 SQL문이 아닌 조건에 맞게 동적으로 쿼리 생성
  • 비슷한 쿼리 재사용 가능 및 가독성 향상
  • 문자열이 아닌 자바 소스코드로 작성됨 (컴파일 시 오류 발견 ㅆㄱㄴ)
  • IDE 도움을 받아 자동 완성까지 지원!

Querydsl 설정하기

gradle 버전

JPAQueryFactory로 상품 조회하기

-> ItemRepositoryTest

	@PersistenceContext
    EntityManager em;
    
 	@Test
    @DisplayName("Querydsl 조회 테스트1")
    public void queryDslTest(){
        this.createItemList();
        JPAQueryFactory queryFactory = new JPAQueryFactory(em); // 쿼리를 동적으로 생성
        QItem qItem = QItem.item; // 쿼리 생성위해 자동생성된 QItem 객체 사용
        JPAQuery<Item> query = queryFactory.selectFrom(qItem)
                .where(qItem.itemSellStatus.eq(ItemSellStatus.SELL))
                .where(qItem.itemDetail.like("%" + "테스트 상품 상세 설명" + "%"))
                .orderBy(qItem.price.desc());

        List<Item> itemList = query.fetch(); // 쿼리 결과를 리스트로 반환, fetch(0 시점에 쿼리문 실행

        for(Item item : itemList){
            System.out.println(item.toString());
        }
    }
  • @PersistenceContext : 영속컨텍스트 사용하기 위해 EntityManager 빈을 주입
  • QItem : QueryDSL전용 엔티티 (간단한 쿼리는 (Spring Data)JPA를 사용하고, 동적쿼리는 QueryDSL을 사용하여 개발하곤 합니다.)

JPAQuery 데이터 반화 메소드

메소드내용
List<T> fetch()조회 결과 리스트 반환
T fetchOne조회 대상이 1건인 경우 제네릭으로 지정한 타입 반환
T fetchFirst()조회 대상 중 1건만 반환
Long fatchCount()조회 대상 개수 반환
QueryResult<T> fetchResults()조회한 리스트와 전체 개수를 포함한 QueryResults 반환

실행결과

Hibernate:
select
	item0_.item_id as item_id1_0_,
    item0_.item_detail as item_det2_0_,
    item0_.item_nm as item_nm3_0_,
    item0_.item_sell_status as item_sel4_0_,
    item0_.price as price5_0_,
    item0_.rec_time as reg_time6_0_,
    item0_.stock_number as stock_nu7_0_,
    item0_.update_time as update_t8_0_,
from
	item item0_
where
	item0_.item_sell_status=?
    and(
    	item-_.item_detail like ? escape '!'
    )
order by
	item0_.price desc

QuerydslPredicateExecutor를 이용한 상품 조회를 해보자

Predicate란?

'이 조건이 맞다'고 판단하는 근거를 함수로 제공하는 것

-> ItemRepository

public interface ItemRepository extends JpaRepository<Item, Long>,
        QuerydslPredicateExecutor<Item> {
  • Pepository에 Predicate를 파라미터로 전달하기 위해 코드 수정

QueryDslPredicateExecutor 인터페이스 제공 메소드

메소드내용
long count(Predicate)조건에 맞는 데이터 총 개수 반환
boolean exists(Predicate)조건에 맞는 데이터 존재 여부 반환
Iterator findAll(Predicate)조건에 맞는 모든 데이터 반환
Page<T> findAll(Predicate, Pageable)조건에 맞는 페이지 데이터 반환
Iterator findAll(Predicate, Sort)조건에 맞는 정렬된 데이터 반환
T findOne(Predicate)조건에 맞는 데이터 1개 반환

-> ItemRepository

public void createItemList2(){
        for(int i=1;i<=5;i++){
            Item item = new Item();
            item.setItemNm("테스트 상품"+i);
            item.setPrice(10000 + i);
            item.setItemDetail("테스트 상품 상세 설명"+i);
            item.setItemSellStatus(ItemSellStatus.SELL);
            item.setStockNumber(100);
            item.setRegTime(LocalDateTime.now());
            item.setUpdateTime(LocalDateTime.now());
            itemRepository.save(item);
        }

        for(int i=6;i<=10;i++){
            Item item = new Item();
            item.setItemNm("테스트 상품"+i);
            item.setPrice(10000 + i);
            item.setItemDetail("테스트 상품 상세 설명"+i);
            item.setItemSellStatus(ItemSellStatus.SOLD_OUT);
            item.setStockNumber(0);
            item.setRegTime(LocalDateTime.now());
            item.setUpdateTime(LocalDateTime.now());
            itemRepository.save(item);
        }
    }

    @Test
    @DisplayName("상품 Querydsl 조회 테스트2")
    public void queryDslTest2(){

        this.createItemList2();

        BooleanBuilder booleanBuilder = new BooleanBuilder(); // 2: 쿼리에 들어갈 조건을 만들어주는 빌더
        QItem item = QItem.item;

        String itemDetail = "테스트 상품 상세 설명";
        int price = 10003;
        String itemSellStat = "SELL";

        booleanBuilder.and(item.itemDetail.like("%" + itemDetail + "%")); // 3: 조회 시 조건
        booleanBuilder.and(item.price.gt(price));

        if(StringUtils.equals(itemSellStat, ItemSellStatus.SELL)){
            booleanBuilder.and(item.itemSellStatus.eq(ItemSellStatus.SELL));
        }

        Pageable pageable = PageRequest.of(0, 5); // 4: 데이터를 페이징해 조회하도록 Pageble 객체 생성
        Page<Item> itemPagingResult =
                itemRepository.findAll(booleanBuilder, pageable); // 5: 조건에 맞는 데이터를 Page 객체로 받아옴.
        System.out.println("total elements : " +
                itemPagingResult. getTotalElements());

        List<Item> resultItemList = itemPagingResult.getContent();
        for(Item resultItem: resultItemList){
            System.out.println(resultItem.toString());
        }
    }
  • createItemList2 : 1~10까진 SELL, 11~20까진 SOLDOUT
  • BooleanBuilder : 동적으로 쿼리를 생성해주면서 조건까지 넣을 꺼임
  • .and : 조회 시 사용할 조건들을 설정
  • Pageable : 페이지를 어떻게 보여줄지 정보를 전달하는 API
  • PageRequest : 몇 페이지, 한 페이지의 사이즈, Sorting 방법(Option)을 가지고, Repository에 Paging을 요청할 때 사용하는 것
    [ 첫번째 인자 : 조회할 페이지 번호, 두번째 : 한 페이지당 조회할 데이터 개수]

실행결과

Hibernate:
select
	item0_.item_id as item_id1_0_,
    item0_.item_detail as item_det2_0_,
    item0_.item_nm as item_nm3_0_,
    item0_.item_sell_status as item_sel4_0_,
    item0_.price as price5_0_,
    item0_.rec_time as reg_time6_0_,
    item0_.stock_number as stock_nu7_0_,
    item0_.update_time as update_t8_0_,
from
	item item0_
where
	(
		item0_.item_detail like ? escape '!'
    )
    and item0_.price>?
    and item0_.item_sell_status=? limit ?

0개의 댓글

관련 채용 정보