DevBoi

[JPA] QueryDsl 사용하기 본문

Develop/[JPA]

[JPA] QueryDsl 사용하기

HiSmith 2023. 5. 2. 22:48
반응형

사용을 위한 기본구성

 

1. JpaFactory

package com.practice.demo.config;

import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.persistence.EntityManager;

@Configuration
public class JpaFactory {

  @Autowired
  EntityManager em;

  @Bean
  public JPAQueryFactory jpaQueryFactory(){
    return new JPAQueryFactory(em);
  }
}

 

2.Book

package com.practice.demo.domain;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import javax.persistence.*;

@Entity
@Getter
@Setter
@NoArgsConstructor
public class Book {

  @Id @GeneratedValue(strategy = GenerationType.AUTO)
  private Long bookId;

  @Column
  private String bookName;

}

 

3. BookRepository

package com.practice.demo.repository;

import com.practice.demo.domain.Book;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface BookRepository extends JpaRepository<Book,Long> {

}

 

4. BookController

package com.practice.demo.controller;

import com.practice.demo.domain.Book;
import com.practice.demo.domain.QBook;
import com.practice.demo.repository.BookRepository;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class BookController {

  @Autowired
  private JPAQueryFactory query;

  @Autowired
  BookRepository bookRepository;
  @RequestMapping("/insert")
  public void insertBook(){
    Book b1 = new Book();
    bookRepository.save(b1);
  }
  @RequestMapping("/get")
  public List<Book> insertBook2(){
    return query.selectFrom(QBook.book).fetch();
  }
}

 

간단하게 insert,select 를 하는 동작을 하는 걸 구현해봤다.

몇가지 추가적으로 개발을 한 내용은 아래와같다.

 @RequestMapping("/get1")
  public List<Book> get2(){
    //
    List<Book> list = query.selectFrom(QBook.book).where(QBook.bookId.between(1L,2L )).fetch();

    //같은지 체크
    return query.selectFrom(QBook.book).where(QBook.bookId.eq(1L)).fetch();
  }

조건문에 대한건 코드 추천으로 더 활용가능하다.

 

추가적으로 궁금한것은 그때 찾아봤다.

 

1. fetch()와 fetchall()의 차이는?

우선 return 문이 다르다.

그니까, 쉽게 말하면 목적에 따라서 다르다기보다 

아예 기능자체가 다른것이다.

 

fetchr관련 사용은 위와 같다.

한개냐 페이징이냐, 개수냐 에 따라서 다르게 쓰는것이다.

그러면... fetchall은 무엇에 쓰는걸까?

 @Override
    public Q fetchAll() {
        return queryMixin.fetchAll();
    }
@Override
    @SuppressWarnings("unchecked")
    public List<T> fetch() {
        try {
            Query query = createQuery();
            return (List<T>) getResultList(query);
        } finally {
            reset();
        }
    }

우선 정의된 클래스의 이름도 다르다.,

fetch()는 AbstactJPAQuery에 존재하고

fetchAll()은 JPAQueryBase에 존재한다.

fetchAll()은 Q엔티티를 리턴하는것으로 보아, join이나 여러개의 엔티티를 복합적으로 사용시에 사용하는 것이고

fetch()는 결과에 대한 리턴을 받고자 할 때 사용한다.

 

 

 

2. Qbook을 static 하게 사용하는 방법은?

List<Book> list = query.selectFrom(QBook.book).where(QBook.book.bookId.between(1L,2L )).fetch();

    //같은지 체크
    return query.selectFrom(QBook.book).where(QBook.book.bookId.eq(1L)).fetch();

요로케 사용했었는데

매번, Q클래스를 타고 가는게 귀찮다.

이럴떄는 static 하게 선언하고, 북으로 바로가는게 좋다.

맥 기준 옵션 +엔터치면 스태택으로 변경할 수 있도록 설정가능하고

이를 설정하게 되면, import문이 이렇게 바뀐다.

 

이러면 좀 더 깔끔하게 사용이 가능하다.

3. 정렬하는 법은?

List<Book> list = query.selectFrom(book).where(
                      book.bookId.between(1L,2L ),
                      book.bookName.eq("gd")
                          ).orderBy(book.bookName.desc())
      .fetch();

 

4. where 절의 조건이 여러개일때는?

List<Book> list = query.selectFrom(book).where(
                      book.bookId.between(1L,2L ),
                      book.bookName.eq("gd")
                          ).fetch();

where 절에 콤마를 붙이면 기본적으로 and 연산이 된다.

 

 

 

기본적인 사용방법은 위와 같다.

궁금증도 해결했고 이제 기초를 해봤으니, 어느정도 심화 개념을 공부하면서, 

프로젝트를 써보면 좀더 깊이 있게 사용할 수 있을 듯하다.

 

페이징 처리 해보기

offset,limit을 사용하면 된다.

다만 좀 특이한게 fetch가 아니라 fetchResult로 사용할 수 있다.

이는 페이징 관련 내용을 사용할 수 있도록 객체로 리턴해주는 것이다.

  @RequestMapping("/page")
  public List<Book> page(){
    //같은지 체크
    QueryResults<Book> result =  query.selectFrom(book)
      .where(book.bookId.eq(1L))
      .offset(0)
      .limit(10)
      .fetchResults();
    List<Book> resultData = result.getResults();
    long offset = result.getOffset();
    long limit = result.getLimit();
    long total = result.getTotal();
  return resultData;
  }

 

페이징 처리할때 필요한 요소들을 전부 리턴해준다.

이를 객체로 하던, 별도 맵으로 하던은 자기 마음대로이겠지만 ..

 

 

 

다음에는 엔티티 몇개를 더 만들어서 조인이랑 여러가지 기본적인 동작을 해보자

반응형