[QueryDSL] 7. ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA๊ฐ€ ์ œ๊ณตํ•˜๋Š” Querydsl ๊ธฐ๋Šฅ

2022. 10. 18. 14:45ใ†์ธํ”„๋Ÿฐ/์‹ค์ „! QueryDSL

728x90

https://www.inflearn.com/course/Querydsl-%EC%8B%A4%EC%A0%84/dashboard

 

์‹ค์ „! Querydsl - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜

Querydsl์˜ ๊ธฐ์ดˆ๋ถ€ํ„ฐ ์‹ค๋ฌด ํ™œ์šฉ๊นŒ์ง€, ํ•œ๋ฒˆ์— ํ•ด๊ฒฐํ•ด๋ณด์„ธ์š”!, - ๊ฐ•์˜ ์†Œ๊ฐœ | ์ธํ”„๋Ÿฐ...

www.inflearn.com

ํ•ด๋‹น ๊ฐ•์˜๋ฅผ ๋“ฃ๊ณ  ์ •๋ฆฌํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค. ๐Ÿ˜€๐Ÿ˜Ž๐Ÿฅฐ

 

 

โ— ์ด๋ฒˆ ๊ฐ•์˜์—์„œ๋Š” ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA๊ฐ€ ์ œ๊ณตํ•˜๋Š” Querydsl ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด์„œ ์†Œ๊ฐœํ•˜๋Š”๋ฐ ์—ฌ๊ธฐ์„œ ์†Œ๊ฐœํ•˜๋Š” ๊ธฐ๋Šฅ๋“ค์€ ๋‹จ์ˆœํ•œ ๊ฒฝ์šฐ์—๋Š” ํŽธํ•˜์ง€๋งŒ ์ œ์•ฝ์ด ์ปค์„œ ๋ณต์žกํ•œ ์‹ค๋ฌด ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ์—๋Š” ๋งŽ์ด ๋ถ€์กฑํ•œ ํŽธ์ด๋ผ๊ณ  ํ•œ๋‹ค. 

๊ทธ๋Ÿผ์—๋„ ์ผ๋‹จ ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ„๋‹จํžˆ ์†Œ๊ฐœํ•˜๊ณ  ์™œ ๋ถ€์กฑํ•œ์ง€ ์„ค๋ช…ํ•ด์ค€๋‹ค๊ณ  ํ•œ๋‹ค. 

 

 

 

1๏ธโƒฃ ์ธํ„ฐํŽ˜์ด์Šค ์ง€์› - QuerydslPredicateExecutor

- ๊ณต์‹ url 

https://docs.spring.io/spring-data/jpa/docs/2.2.3.RELEASE/reference/html/ #core.extensions.querydsl

 

QuerydslPredicateExecutor ์ธํ„ฐํŽ˜์ด์Šค

 

๋ฆฌํฌ์ง€ํ† ๋ฆฌ์— ์ ์šฉ

MemberRepository

 

 

๋™์ž‘ ํ™•์ธ 

MemberRepositoryTest

์‚ฌ์šฉํ•  ๋•Œ ๋ณด๋ฉด 

memberRepository.findAll(member.age.between(10, 40).and(member.username.eq("member1")); 

์ด๋ ‡๊ฒŒ ์ง€์ •ํ•ด์ฃผ๋ฉด 

์ง€์ •ํ•œ ์กฐ๊ฑด์— ๋งž๊ฒŒ ์ฟผ๋ฆฌ๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

 

โญ ํ•œ๊ณ„์  โญ

- ์กฐ์ธ์„ ํ•  ์ˆ˜ ์—†๋‹ค.(๋ฌต์‹œ์  ์กฐ์ธ์€ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ left join์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.)
- ํด๋ผ์ด์–ธํŠธ๊ฐ€ Querydsl์— ์˜์กดํ•ด์•ผ ํ•œ๋‹ค. ์ฆ‰, ์„œ๋น„์Šค ํด๋ž˜์Šค๊ฐ€ Querydsl์ด๋ผ๋Š” ๊ตฌํ˜„ ๊ธฐ์ˆ ์— ์˜์กดํ•ด์•ผ ํ•œ๋‹ค. 
- ๋ณต์žกํ•œ ์‹ค๋ฌดํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ์—๋Š” ํ•œ๊ณ„๊ฐ€ ๋ช…ํ™•ํ•˜๋‹ค. 

left join์ด ์•ˆ๋˜๋ฉด ์‹ค๋ฌด์—์„œ ๊ฑฐ์˜ ์‚ฌ์šฉํ•˜๊ธฐ ํž˜๋“ค๊ณ ... ๋‹จ์ˆœ ํ…Œ์ด๋ธ” ํ•˜๋‚˜๊ฐ€์ง€๊ณ ๋งŒ ํ•  ๋•Œ ์ •๋„๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.. 

ํ•œ๊ณ„๊ฐ€ ๋ช…ํ™•ํ•จ..! ์‚ฌ์šฉ ๊ถŒ์žฅํ•˜์ง€ ์•Š์Œ 

 

โ— ์ฐธ๊ณ ๋กœ QuerydslPredicateExecutor๋Š” Pageable, Sort๋ฅผ ๋ชจ๋‘ ์ง€์›ํ•˜๊ณ  ์ •์ƒ ๋™์ž‘ํ•œ๋‹ค. 

 

 

 

 

2๏ธโƒฃ Querydsl Web ์ง€์› 

๊ณต์‹ url: https://docs.spring.io/spring-data/jpa/docs/2.2.3.RELEASE/reference/html/#core.web.type-safe

 

Spring Data JPA - Reference Documentation

Example 108. Using @Transactional at query methods @Transactional(readOnly = true) public interface UserRepository extends JpaRepository { List findByLastname(String lastname); @Modifying @Transactional @Query("delete from User u where u.active = false") v

docs.spring.io

 

์ด๋Ÿฐ์‹์œผ๋กœ ํŒŒ๋ผ๋ฏธํ„ฐ์— ์ง€์ •ํ•ด์ฃผ๋ฉด 

์ด๋ ‡๊ฒŒ ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์„ ์ฃผ๋ฉด 

์ด๋Ÿฐ์‹์œผ๋กœ ๋ฐ”๊ฟ”์ค€๋‹ค๋Š” ๋ง์ด๋‹ค. 

 

 

-> ์ด๊ฑด ๊ฐ•์˜์—์„œ ์ฝ”๋“œ๋„ ์ž‘์„ฑ์•ˆํ•˜๊ณ  ๊ณต์‹ url๋งŒ ๋ณด๊ณ  ๋„˜์–ด๊ฐ„๊ฑด๋ฐ ๊ทธ์ •๋„๋กœ ์‚ฌ์šฉ ๊ถŒ์žฅ์„ ์•„์˜ˆ ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค..!

๊ฐ•์˜์—์„œ ์ฝ”๋“œ๋„ ์—†์ด ์„ค๋ช…ํ•˜๋Š”๊ฑด ์ด๊ฒŒ ๊ฑฐ์˜ ์ฒ˜์Œ์ด์—ˆ๋˜๊ฑฐ ๊ฐ™๋‹ค ใ…‹ใ…‹ใ…‹ ๊ทธ๋งŒํผ ์•ˆ์ค‘์š”ํ•˜๋‹ค๋Š” ๊ฑฐ๊ฒ ์ง€~~

 

 

โญ ํ•œ๊ณ„์  โญ

- ๋‹จ์ˆœํ•œ ์กฐ๊ฑด๋งŒ ๊ฐ€๋Šฅ 
- ์กฐ๊ฑด์„ ์ปค์Šคํ…€ํ•˜๋Š” ๊ธฐ๋Šฅ์ด ๋ณต์žกํ•˜๊ณ  ๋ช…์‹œ์ ์ด์ง€ ์•Š์Œ
- ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ Querydsl์— ์˜์กด
- ๋ณต์žกํ•œ ์‹ค๋ฌดํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ์—๋Š” ํ•œ๊ณ„๊ฐ€ ๋ช…ํ™• 

๋‹จ์ˆœํ•œ ์กฐ๊ฑด์ด ๊ฑฐ์˜ eq, in, contains ์ •๋„๊ฐ€ ์žˆ๊ณ , ๊ฑฐ์˜ ์ด์ •๋„๋งŒ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•œ๋‹ค. 

๊ทธ๋ฆฌ๊ณ  ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ Querydsl์— ์˜์กดํ•˜๋Š”๊ฒŒ ํ•œ๊ณ„์ ์ธ ์ด์œ ๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ Querydsl์— ์˜์กดํ•˜๊ฒŒ ๋˜๋ฉด ๋‚˜์ค‘์— ๊ตฌํ˜„ ๊ธฐ์ˆ ์„ ๋ฐ”๊พธ๊ฒŒ ๋˜๋ฉด ์ „์ฒด๋ฅผ ๋‹ค ๋ฐ”๊ฟ”์ค˜์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์œ ์ง€๋ณด์ˆ˜ ์ธก๋ฉด์—์„œ ์•ˆ์ข‹์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. 

 

 

 

3๏ธโƒฃ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ์ง€์› - QuerydslRepositorySupport

 

QuerydslRepositorySupport

 

 

MemberRepositoryImpl

MemberRepositoryImpl์— QuerydslRepositorySupport๋ฅผ ์ƒ์†๋ฐ›์•„์„œ ์‚ฌ์šฉํ•ด์ฃผ๋ฉด ๋˜๋Š”๋ฐ, ์ด๋•Œ ์ƒ์„ฑ์ž๋Š” ์ด๋Ÿฐ์‹์œผ๋กœ ๋ฐ›์•„์™€์•ผ ํ•œ๋‹ค. 

 

 

QuerydslRepositorySupport๋Š” Querydls3์„ ์ง€์›?ํ•˜๊ธฐ ๋•Œ๋ฌธ์— select๊ฐ€ ๋จผ์ €๊ฐ€ ์•„๋‹ˆ๋ผ select๊ฐ€ ๊ฐ€์žฅ ๋’ค์— ๋‚˜์˜จ๋‹ค. 

from์ด ๊ฐ€์žฅ ๋จผ์ € ๋‚˜์˜ค๋Š” ํ˜•์‹ 

 

 

QuerydslRepositorySupport๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํŽ˜์ด์ง•์„ ํ•  ๋•Œ๋Š” 

getQuerydsl().applyPagination()์— ํŽ˜์ด์ง•๊ณผ ์ฟผ๋ฆฌ๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ฃผ๋ฉด ๋œ๋‹ค. 

๊ทธ๋ฆฌ๊ณ  ๊ฒฐ๊ณผ์— ๋Œ€ํ•ด์„œ ๋‹ค์‹œ getReulstsํ•˜๋ฉด ๋œ๋‹ค. 

 

applyPagination()์— offset, limit์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด ๊ฐ’๋“ค์€ ์ƒ๋žตํ•ด์ค˜๋„ ๋œ๋‹ค. 

 

 

์žฅ์ 

- getQuerydsl().applyPagination() : ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ํŽ˜์ด์ง•์„ Querydsl๋กœ ํŽธ๋ฆฌํ•˜๊ฒŒ ๋ณ€ํ™˜ ๊ฐ€๋Šฅํ•˜๋‹ค. 
(๊ทผ๋ฐ Sort๋Š” ์˜ค๋ฅ˜ ๋ฐœ์ƒํ•œ๋‹ค..)
- from()์œผ๋กœ ์‹œ์ž‘ ๊ฐ€๋Šฅ -> ์ด๊ฒƒ๋„ ์ตœ๊ทผ์—๋Š” QueryFactory๋ฅผ ์‚ฌ์šฉํ•ด์„œ select()๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์ด ๋” ๋ช…์‹œ์ ์ด๋‹ค. 
- EntityManager ์ œ๊ณต 

 

๋‹จ์ 

- Querydsl 3.x ๋ฒ„์ „์„ ๋Œ€์ƒ์œผ๋กœ ๋งŒ๋“ฆ 
- Qeurydsl 4.x์— ๋‚˜์˜จ JpaQueryFactory๋กœ ์‹œ์ž‘ํ•  ์ˆ˜ ์—†์Œ.
- QueryFactory๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š์Œ
- ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ Sort ๊ธฐ๋Šฅ์ด ์ •์ƒ ๋™์ž‘ํ•˜ ์ง€์•Š์Œ,, 

 

 

 

4๏ธโƒฃ Querydsl ์ง€์› ํด๋ž˜์Šค ์ง์ ‘ ๋งŒ๋“ค๊ธฐ 

: ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ๊ฐ€ ์ œ๊ณตํ•˜๋Š” QuerydslRepositorySupport๊ฐ€ ์ง€๋‹Œ ํ•œ๊ณ„๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ ๊ทน๋ณตํ•˜๊ธฐ ์œ„ํ•ด ์ง์ ‘ Querydls ์ง€์› ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ ๋‹ค! 

 

์žฅ์ 

- ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ํŽ˜์ด์ง•์„ ํŽธ๋ฆฌํ•˜๊ฒŒ ๋ณ€ํ™˜ 
- ํŽ˜์ด์ง•๊ณผ ์นด์šดํŠธ ์ฟผ๋ฆฌ ๋ถ„๋ฆฌ ๊ฐ€๋Šฅ 
- ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ Sort ์ง€์›
- select(), selectFrom() ์œผ๋กœ ์‹œ์ž‘ ๊ฐ€๋Šฅ
- EntityManager(), QueryFactory ์ œ๊ณต 

 

 

Querydsl4RepositorySupport

package study.querydesl.repository.support;

import com.querydsl.core.types.EntityPath;
import com.querydsl.core.types.Expression;
import com.querydsl.core.types.dsl.PathBuilder;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import
        org.springframework.data.jpa.repository.support.JpaEntityInformationSupport;
import org.springframework.data.jpa.repository.support.Querydsl;
import org.springframework.data.querydsl.SimpleEntityPathResolver;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.stereotype.Repository;
import org.springframework.util.Assert;

import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import java.util.List;
import java.util.function.Function;

/**
 * Querydsl 4.x ๋ฒ„์ „์— ๋งž์ถ˜ Querydsl ์ง€์› ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
 *
 * @author Younghan Kim
 * @see org.springframework.data.jpa.repository.support.QuerydslRepositorySupport
 */
@Repository
public abstract class Querydsl4RepositorySupport {
    private final Class domainClass;
    private Querydsl querydsl;
    private EntityManager entityManager;
    private JPAQueryFactory queryFactory;

    public Querydsl4RepositorySupport(Class<?> domainClass) {
        Assert.notNull(domainClass, "Domain class must not be null!");
        this.domainClass = domainClass;
    }

    @Autowired
    public void setEntityManager(EntityManager entityManager) {
        Assert.notNull(entityManager, "EntityManager must not be null!");
        JpaEntityInformation entityInformation =
                JpaEntityInformationSupport.getEntityInformation(domainClass, entityManager);
        SimpleEntityPathResolver resolver = SimpleEntityPathResolver.INSTANCE;
        EntityPath path = resolver.createPath(entityInformation.getJavaType());
        this.entityManager = entityManager;
        this.querydsl = new Querydsl(entityManager, new
                PathBuilder<>(path.getType(), path.getMetadata()));
        this.queryFactory = new JPAQueryFactory(entityManager);
    }

    @PostConstruct
    public void validate() {
        Assert.notNull(entityManager, "EntityManager must not be null!");
        Assert.notNull(querydsl, "Querydsl must not be null!");
        Assert.notNull(queryFactory, "QueryFactory must not be null!");
    }

    protected JPAQueryFactory getQueryFactory() {
        return queryFactory;
    }

    protected Querydsl getQuerydsl() {
        return querydsl;
    }

    protected EntityManager getEntityManager() {
        return entityManager;
    }

    protected <T> JPAQuery<T> select(Expression<T> expr) {
        return getQueryFactory().select(expr);
    }

    protected <T> JPAQuery<T> selectFrom(EntityPath<T> from) {
        return getQueryFactory().selectFrom(from);
    }

    protected <T> Page<T> applyPagination(Pageable pageable,
                                          Function<JPAQueryFactory, JPAQuery> contentQuery) {
        JPAQuery jpaQuery = contentQuery.apply(getQueryFactory());
        List<T> content = getQuerydsl().applyPagination(pageable,
                jpaQuery).fetch();
        return PageableExecutionUtils.getPage(content, pageable,
                jpaQuery::fetchCount);
    }

    protected <T> Page<T> applyPagination(Pageable pageable,
                                          Function<JPAQueryFactory, JPAQuery> contentQuery, Function<JPAQueryFactory,
            JPAQuery> countQuery) {
        JPAQuery jpaContentQuery = contentQuery.apply(getQueryFactory());
        List<T> content = getQuerydsl().applyPagination(pageable,
                jpaContentQuery).fetch();
        JPAQuery countResult = countQuery.apply(getQueryFactory());
        return PageableExecutionUtils.getPage(content, pageable,
                countResult::fetchCount);
    }
}

QuerydslRepositorySupprot๊ฐ€ QueryFactory๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ ๋งž์ถ”๊ธฐ ์œ„ํ•ด์„œ ๊ฐ•์‚ฌ๋‹˜์ด ์ง์ ‘ ๋งŒ๋“  ๊ฒƒ์œผ๋กœ 

์ด๊ฑด ์ž๋ฐ” 8 ๊ธฐ๋Šฅ์ด ์‚ฌ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฐ ์‚ฌํ•ญ์„ ์ข€ ์•Œ๊ณ  ์žˆ์–ด์•ผ ์ดํ•ด ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๋‹ค. 

 

 

 

Querydsl4RepositorySupport ์‚ฌ์šฉ ์ฝ”๋“œ 

MemberTestRepository

Querydsl4RepositorySupport๋ฅผ ์ƒ์†๋ฐ›๊ณ , basicSelect()๋ฅผ ๋ณด๋ฉด queryFactory ์—†์ด select๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. 

(Querydsl4RepositorySupport์— ๊ตฌํ˜„๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ) 

 

applyPagination()์€ ์œ„์— searchPageByApplyPage()๋ฅผ ์ถ”์ƒํ™”ํ•œ Querydsl4RepositorySupport๋ฅผ ์‚ฌ์šฉํ•ด ์ข€ ๋” ๊ฐ„๋‹จํ•˜๊ฒŒ ์ž‘์„ฑํ•œ ์ฝ”๋“œ์ด๋‹ค.

๋ณด๋ฉด List<T> content ๋ถ€๋ถ„๊ณผ  PageableExecutionUtils๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๊ฑฐ ๋ณด๋ฉด ์œ„์— ์ฝ”๋“œ์™€ ๋™์ผํ•œ ์ฝ”๋“œ๋ฅผ Querydsl4RepositorySupport๋กœ ๋นผ๋‘” ๊ฒƒ์ด๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  ์ด์ „์— ํŽ˜์ด์ง• ๊ด€๋ จ ์ฝ”๋“œ๋ฅผ ์งค ๋•Œ ์นด์šดํŠธ ์ฟผ๋ฆฌ๋ฅผ ๋”ฐ๋กœ ๋บ€ Complex ๋ฒ„์ „์„ ๋งŒ๋“ค์—ˆ์—ˆ๋Š”๋ฐ, 

contentQuery ๋‹ค์Œ์— countQuery๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋œ๋‹ค. 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90