Predicate vs BooleanExpression

coldrice99·3일 전
0
post-thumbnail

QueryDSL에서 Predicate와 BooleanExpression의 차이

QueryDSL을 사용하다 보면 PredicateBooleanExpression 두 가지 타입을 자주 마주치게 됩니다. 둘 다 쿼리의 조건을 표현하는 데 사용되지만, 사용 목적특징이 조금 다릅니다. 이번 TIL에서는 이 두 타입의 차이를 정리하고, 언제 어떤 것을 사용해야 하는지 예제를 통해 알아보겠습니다.


Predicate와 BooleanExpression의 정의

1. Predicate

Predicate는 QueryDSL에서 조건을 표현하는 가장 일반적인 인터페이스입니다. QueryDSL의 다양한 조건 표현식을 처리할 수 있는 범용적인 타입입니다.

  • 특징:
    • 모든 조건을 담을 수 있는 상위 타입으로 설계되었습니다.
    • 조건 조합(and, or) 같은 고급 기능은 제공하지 않습니다.
    • QueryDSL API에서 기본적으로 요구하는 조건 타입으로 자주 사용됩니다.

2. BooleanExpression

BooleanExpressionPredicate구체적인 구현체입니다. QueryDSL에서 Boolean 타입의 조건을 명확하게 표현하고, 조건 조합을 쉽게 할 수 있는 추가 메서드를 제공합니다.

  • 특징:
    • and, or, not 등 조건을 결합할 수 있는 메서드를 제공합니다.
    • 동적 조건 생성이 필요한 경우에 적합합니다.
    • Predicate보다 더 구체적이고, 복잡한 조건 작성에 유리합니다.

코드 비교

1. Predicate 사용

Predicate는 단순 조건을 전달하거나, QueryDSL API에서 기본 조건 타입으로 사용됩니다.

private Predicate titleContains(String keyword) {
    return keyword != null ? QTodo.todo.title.contains(keyword) : null;
}

// 사용 예시
Predicate condition = titleContains("project");

List<Todo> todos = queryFactory
    .selectFrom(QTodo.todo)
    .where(condition) // 단일 조건 사용
    .fetch();

2. BooleanExpression 사용

BooleanExpression은 조건 조합과 동적 조건 생성을 지원합니다.

private BooleanExpression titleContains(String keyword) {
    return keyword != null ? QTodo.todo.title.contains(keyword) : null;
}

private BooleanExpression createdDateBetween(LocalDateTime startDate, LocalDateTime endDate) {
    return startDate != null && endDate != null
        ? QTodo.todo.createdAt.between(startDate, endDate)
        : null;
}

// 사용 예시
BooleanExpression condition = titleContains("project")
    .and(createdDateBetween(LocalDateTime.now().minusDays(7), LocalDateTime.now()));

List<Todo> todos = queryFactory
    .selectFrom(QTodo.todo)
    .where(condition) // 복합 조건 사용
    .fetch();

Predicate와 BooleanExpression의 사용 상황

1. 단일 조건만 사용하는 경우

Predicate는 간단한 단일 조건을 전달하는 데 적합합니다.

private Predicate titleContains(String keyword) {
    return keyword != null ? QTodo.todo.title.contains(keyword) : null;
}

// 단순 조건 전달
Predicate condition = titleContains("meeting");

List<Todo> todos = queryFactory
    .selectFrom(QTodo.todo)
    .where(condition)
    .fetch();

2. 여러 조건을 조합해야 하는 경우

BooleanExpression은 and, or 메서드를 통해 여러 조건을 결합할 때 유리합니다.

private BooleanExpression titleContains(String keyword) {
    return keyword != null ? QTodo.todo.title.contains(keyword) : null;
}

private BooleanExpression createdDateBetween(LocalDateTime startDate, LocalDateTime endDate) {
    return startDate != null && endDate != null
        ? QTodo.todo.createdAt.between(startDate, endDate)
        : null;
}

// 복합 조건
BooleanExpression condition = titleContains("meeting")
    .and(createdDateBetween(LocalDateTime.now().minusDays(30), LocalDateTime.now()));

List<Todo> todos = queryFactory
    .selectFrom(QTodo.todo)
    .where(condition)
    .fetch();

상황별 구분 기준

상황PredicateBooleanExpression
단일 조건 사용적합가능
복잡한 조건 조합부적합적합
조건을 동적으로 추가해야 할 때제한적적합
QueryDSL API에서 기본 조건 전달적합가능
and, or, not 같은 조건 조합불가능가능

장점 요약

  1. Predicate:

    • 범용적이고 단순한 조건을 처리할 때 적합.
    • QueryDSL API가 기본적으로 지원하는 타입으로 활용하기 쉬움.
  2. BooleanExpression:

    • 동적 조건 생성 및 조합이 필요한 경우 적합.
    • 가독성과 유지보수성이 뛰어남.
    • 복잡한 조건을 처리할 때 강력한 도구.

느낀 점

이번에 Predicate와 BooleanExpression의 차이를 정리하면서, 상황에 맞게 적절한 타입을 선택하는 것이 중요하다는 것을 다시 느꼈습니다. 실무에서는 대부분 복잡한 조건 조합이 필요하기 때문에 BooleanExpression을 사용하는 경우가 더 많을 것 같습니다. 하지만 간단한 조건만 필요한 경우에는 Predicate를 사용해 코드의 간결함을 유지할 수 있겠죠.


결론

  • 단일 조건이나 간단한 사용에는 Predicate가 적합.
  • 복잡한 조건 조합이나 동적 조건 생성이 필요하면 BooleanExpression을 사용.
  • 실무에서는 조건 조합이 많은 경우가 많아 BooleanExpression을 기본으로 활용하되, 상황에 따라 Predicate로 간단히 처리할 수 있습니다.
profile
서두르지 않으나 쉬지 않고

0개의 댓글