[JPA] JPQL -> QueryDsl 마이그레이션, 동적쿼리 적용

yookyungmin·2023년 9월 11일
0

기존의 코드랩 프로젝트에서 QueryDsl을 써보았기 때문에 은행 입출금 프로젝트에서 JPQL 동적쿼리로 작성한 걸 Querydsl 설정을 추가하고 적용한 내용을 블로그 포스팅 해보려고 합니다.

bilud.gradle

buildscript {
	ext {
		queryDslVersion = "5.0.0"
	}
}

plugins {
	id 'java'
	id 'org.springframework.boot' version '2.7.13'
	id 'io.spring.dependency-management' version '1.0.15.RELEASE'
	id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
}

group = 'shop.mtcoding'
version = '0.0.1-SNAPSHOT'

java {
	sourceCompatibility = '11'
}

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
	querydsl.extendsFrom compileClasspath
}

repositories {
	mavenCentral()
}

dependencies {
	// https://mvnrepository.com/artifact/com.auth0/java-jwt
	implementation group: 'com.auth0', name: 'java-jwt', version: '4.2.1'

	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-security'
	implementation 'org.springframework.boot:spring-boot-starter-validation'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	runtimeOnly 'com.h2database:h2'
	runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'

	//Spring security
	implementation 'org.springframework.boot:spring-boot-starter-security'
	testImplementation 'org.springframework.security:spring-security-test'

	// QueryDSL
	implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"
	implementation "com.querydsl:querydsl-apt:${queryDslVersion}"
}
def querydslDir = "$buildDir/generated/querydsl"

querydsl {
	jpa = true
	querydslSourcesDir = querydslDir
}

sourceSets {
	main.java.srcDir querydslDir
}

compileQuerydsl {
	options.annotationProcessorPath = configurations.querydsl
}
tasks.named('test') {
	useJUnitPlatform()
}

jar{
	enabled = false
}

QuerydslConfig

@RequiredArgsConstructor
@Configuration
public class QueryDSLConfig {

    @PersistenceContext
    private final EntityManager em;
sd
    @Bean
    public JPAQueryFactory queryFactory(){
        return new JPAQueryFactory(em);
    }

}

그리고 빌드하는 과정에서 오류가 나서
그래들로 되어있는걸 인텔리제이로 변경하여 해결

JPQL 코드

    @Override
    public List<Transaction> findTransactionList(Long accountId, String gubun, Integer page) {
        //동적쿼리(gubun 값을 가지고 동적쿼리 = DEPOSIOT, WITHDRAW, ALL)
        //JPQL
        String sql = "";
        sql += "select t from Transaction t ";

        if(gubun.equals("WITHDRAW")){
            sql += "join fetch t.withdrawAccount wa ";  //fetch를 지우면 join 해서 데이터를 끌고왔지만 조회는 안한다.
            sql += "where t.withdrawAccount.id = :withdrawAccountId";
        }else if(gubun.equals("DEPOSIT")){
            sql += "join fetch t.depositAccount da ";
            sql += "where t.depositAccount.id = :depositAccountId";
        }else { //gubun = all
            sql += "left join t.withdrawAccount wa ";  //left 뺴면 null값은 조회 안한다 1345
            sql += "left join t.depositAccount da "; // left 빼면 345가 나옴 두번쨰 테이블의 1번이 null이라서
            sql += "where t.withdrawAccount.id = :withdrawAccountId ";
            sql += "or ";
            sql += "t.depositAccount.id = :depositAccountId";
        }

        TypedQuery<Transaction> query = em.createQuery(sql, Transaction.class); //jpql문법

        if(gubun.equals("WITHDRAW")){
            query = query.setParameter("withdrawAccountId", accountId);
        }else if(gubun.equals("DEPOSIT")){
            query = query.setParameter("depositAccountId", accountId);
        }else{
            query = query.setParameter("withdrawAccountId", accountId);
            query = query.setParameter("depositAccountId", accountId);
        }

        query.setFirstResult(page*5); // 5, 10, 15
        query.setMaxResults(5);

        return query.getResultList();
    }

QueryDsl 코드

   @Override
    public List<Transaction> findTransactionList(Long accountId, String gubun, Integer page) {

        JPAQuery<Transaction> query = jpaQueryFactory.selectFrom(transaction);

        if ("WITHDRAW".equals(gubun)) {
            query
                    .innerJoin(transaction.withdrawAccount, QAccount.account)
                    .fetchJoin()
                    .where(withDrawEq(accountId));
        } else if ("DEPOSIT".equals(gubun)) {
            query
                    .innerJoin(transaction.depositAccount, QAccount.account)
                    .fetchJoin()
                    .where(depositEq(accountId));
        } else { // gubun = all
            query
                    .leftJoin(transaction.withdrawAccount, QAccount.account)
                    .leftJoin(transaction.depositAccount, QAccount.account)
                    .where(allEq(accountId));
        }

        return query
                .offset(page * 5)
                .limit(5)
                .fetch();
    }
    private BooleanExpression withDrawEq(Long accountId) {
        return accountId != null ? transaction.withdrawAccount.id.eq(accountId): null;
    }

    private BooleanExpression depositEq(Long accountId) {
        return accountId != null ? transaction.depositAccount.id.eq(accountId): null;
    }

    private BooleanExpression allEq(Long accountId) {
        return accountId != null ? transaction.withdrawAccount.id.eq(accountId).or(transaction.depositAccount.id.eq(accountId)): null;
    }

if else 로 구분 지은 다음에 where 절 안의 쿼리를 booleanExpression을 사용하였습니다.

0개의 댓글