kwonslog / how-to-use-jpa

0 stars 0 forks source link

6회 - JPQL #17

Closed kwonslog closed 1 month ago

kwonslog commented 1 month ago

기본

SQL과 비슷하며 엔티티를 대상으로 쿼리를 실행한다. (SELECT, FROM, WHERE, ORDER BY, GROUP BY 등) 문자열 함수, 수학함수, 날짜함수 등을 제공한다.

제한 된 서브쿼리

SELECT, FROM 절에서는 서브쿼리를 사용 할 수 없다. 주로 WHERE, HAVING 절에서 사용한다. 서브쿼리의 결과는 단일값만 가능하다. 이유는 서브쿼리가 사용되는 위치와 관련이 있다. WHERE 절은 검색 조건을 비교하기 위해 사용하는데 이곳에 사용된 서브쿼리의 결과값 역시 비교를 위한 단일값을 필요로 한다.

함수

문자열 함수

함수 설명 예제 코드
CONCAT 두 개 이상의 문자열을 연결합니다. SELECT CONCAT(e.firstName, ' ', e.lastName) FROM Employee e
SUBSTRING 문자열의 일부를 추출합니다. SELECT SUBSTRING(e.name, 1, 3) FROM Employee e
TRIM 문자열의 앞뒤 공백을 제거합니다. SELECT TRIM(e.name) FROM Employee e
LOWER 문자열을 소문자로 변환합니다. SELECT LOWER(e.name) FROM Employee e
UPPER 문자열을 대문자로 변환합니다. SELECT UPPER(e.name) FROM Employee e
LENGTH 문자열의 길이를 반환합니다. SELECT LENGTH(e.name) FROM Employee e
LOCATE 특정 문자열이 다른 문자열 내에 위치한 인덱스를 반환합니다. SELECT LOCATE('A', e.name) FROM Employee e

수학 함수

함수 설명 예제 코드
ABS 절대값을 반환합니다. SELECT ABS(e.salary) FROM Employee e
SQRT 제곱근을 반환합니다. SELECT SQRT(e.salary) FROM Employee e
MOD 나머지를 반환합니다. SELECT MOD(e.salary, 1000) FROM Employee e
SIZE 컬렉션의 크기를 반환합니다. SELECT SIZE(d.employees) FROM Department d

날짜 함수

함수 설명 예제 코드
CURRENT_DATE 현재 날짜를 반환합니다. SELECT e FROM Employee e WHERE e.hireDate = CURRENT_DATE
CURRENT_TIME 현재 시간을 반환합니다. SELECT e FROM Employee e WHERE e.loginTime = CURRENT_TIME
CURRENT_TIMESTAMP 현재 날짜와 시간을 반환합니다. SELECT e FROM Employee e WHERE e.lastUpdated = CURRENT_TIMESTAMP

컬렉션 함수

함수 설명 예제 코드
SIZE 컬렉션의 크기를 반환합니다. SELECT d FROM Department d WHERE SIZE(d.employees) > 10
IS EMPTY 컬렉션이 비어있는지 확인합니다. SELECT d FROM Department d WHERE d.employees IS EMPTY

조건 함수

함수 설명 예제 코드
COALESCE 첫 번째 null이 아닌 값을 반환합니다. SELECT COALESCE(e.middleName, e.firstName) FROM Employee e
NULLIF 두 값이 같으면 null을, 다르면 첫 번째 값을 반환합니다. SELECT NULLIF(e.firstName, 'John') FROM Employee e
CASE 조건에 따라 다른 값을 반환합니다. SELECT CASE WHEN e.salary >= 100000 THEN 'High' ELSE 'Low' END FROM Employee e

동적 쿼리

Spring Data JPA Specifications 과 QueryDSL 을 많이 사용한다.

차이점 비교

기능 Spring Data JPA Specifications QueryDSL
설정의 용이성 쉬움 (추가 설정 필요 없음) 어려움 (초기 설정과 코드 생성 필요)
타입 세이프 있음 있음
가독성 낮음 (복잡한 코드) 높음 (Fluent API)
기능 강도 제한적 매우 강력
통합성 Spring Data JPA와 자연스럽게 통합 별도 설정 필요
학습 곡선 낮음 높음
다양한 데이터 소스 지원 제한적 광범위한 지원
재사용성 높음 매우 높음

쿼리에 다수의 조건값을 사용해야 하고 조건값이 없더라도 문제없이 처리 하기 위한 상황에는 Specifications 을 사용하는 것이 더 적합하다.

public class PostSpecifications {

    // 이런식으로 조건값을 추가 할 수 있다.
    public static Specification<Post> hasAuthor(String author) {
        return (Root<Post> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
            if (author == null || author.isEmpty()) {
                return null;
            }
            query.orderBy(cb.desc(root.get("author")))
            return cb.equal(root.get("author"), author);
        };
    }

    // Other specifications as needed
}

Root<Post> 는 쿼리의 FROM 절에 해당하는 엔티티이다. 사용한 get 메소드는 해당 엔티티의 속성에 접근 할때 사용한다. CriteriaQuery 는 쿼리에 ORDER BY 를 설정하고 있다. CriteriaBuilder 는 조건값을 적용하기 위해 사용한다.

Specifications 과 Criteria API

Specifications 은 Criteria API 기반으로 작성하는 것이기에 사용하는 방법이 비슷하다. 그래서 가독성 또한 떨어진다. 차이점은 Specifications 은 조건들을 메소드로 분리하고 필요에 따라 재사용 할 수 있다는 장점이 있다.