두 개 이상의 집합에서 각 집합의 모든 원소를 서로 조합해서 가능한 모든 조합을 만들어내는 연산. 두 테이블 간 JOIN 조건이 불충분하거나 누락될 경우 불필요한 데이터가 기하급수적으로 증가할 수 있음. (join 조건을 1=1 식으로 지정하면, 데이터 N개의 테이블과 데이터 M개의 테이블을 join 할 경우 N x M 개의 데이터 호출)
QueryDSL은 Java에서 타입 세이프한 쿼리를 작성할 수 있도록 지원하는 프레임워크. 코드 수준에서 SQL을 추상화하여 작성할 수 있음.
이때, QueryDSL은 테이블을 join 할때 엔티티 간의 연관관계를 기반으로 join 하도록 설계되어 있음.
예시 SQL:
SELECT t.*
FROM todo t
LEFT JOIN manager m ON t.id = m.todo_id
LEFT JOIN user u ON m.user_id = u.id
WHERE t.title LIKE '%title%' AND u.nickname LIKE '%manager%';
위 SQL을 QueryDSL로 표현하면:
List<Todo> todos = jpaQueryFactory
.selectFrom(todo)
.leftJoin(todo.managers, manager)
.leftJoin(manager.user, user)
.where(todo.title.contains("title"), user.nickname.contains("manager"))
.fetch();
일대다 관계를 여러 번 JOIN할 때 중복 데이터가 생성되는 Cartesian product가 발생할 가능성이 큼. - [프로젝트] 카테시안 곱 문제의 발생과 해결
QueryDSL을 사용할 때 아래 사항을 기억할 것
.leftJoin(todo.managers.id, manager.id)와 같이 id로 직접 조인하면 오히려 동작이 불안정하므로 피할 것. (엔티티 기준으로 JOIN해야 함)실제 예시로, countDistinct를 활용하는 법
Long total = jpaQueryFactory
.select(todo.countDistinct())
.from(todo)
.leftJoin(todo.managers, manager)
.leftJoin(manager.user, user)
.where(condition)
.fetchOne();