- Entity 의 매핑정보를 활용하여 쿼리에 적합하도록 쿼리 전용 클래스(Q클래스)로 재구성해주는 기술
- 여기에 JPAQueryFactory 을 통한 Q클래스를 활용할 수 있는 기능들을 제공
- 그럼, JPAQueryFactory 는 뭘까?
- 재구성한 Q클래스를 통해 문자열이 아닌 객체 또는 함수로 쿼리를 작성하고 실행하게 해주는 기술
@PersistenceContext EntityManager em; public List<User> selectUserByUsernameAndPassword(String username, String password){ JPAQueryFactory jqf = new JPAQueryFactory(em); QUser user = QUser.user; List<Person> userList = jpf .selectFrom(user) .where(person.username.eq(username) .and(person.password.eq(password)) .fetch(); return userList; }
이번에 getTodo메서드에서 findByIdWithUser를 QueryDSL로 변경했다.
public TodoResponse getTodo(long todoId) {
Todo todo = todoRepository.findByIdWithUser(todoId)
.orElseThrow(() -> new InvalidRequestException("Todo not found"));
User user = todo.getUser();
return new TodoResponse(
todo.getId(),
todo.getTitle(),
todo.getContents(),
todo.getWeather(),
new UserResponse(user.getId(), user.getEmail()),
todo.getCreatedAt(),
todo.getModifiedAt()
);
}
1. TodoRepositoryQuery 인터페이스
QueryDSL 메서드를 정의하는 인터페이스를 만들었다.
public interface TodoRepositoryQuery {
Optional<Todo> findByIdWithUser(Long todoId);
}
2. TodoRepositoryQueryImpl 클래스
QueryDSL을 이용하여 메서드를 구현
@RequiredArgsConstructor
public class TodoRepositoryQueryImpl implements TodoRepositoryQuery{
private final JPAQueryFactory jpaQueryFactory;
@Override
public Optional<Todo> findByIdWithUser(Long todoId) {
QTodo todo = QTodo.todo;
Todo result = jpaQueryFactory
.selectFrom(todo)
.leftJoin(todo.user).fetchJoin() // N+1 문제 해결
.where(todo.id.eq(todoId))
.fetchOne();
return Optional.ofNullable(result);
}
}
3. TodoRepository 인터페이스
기본 CRUD 메소드가 포함된 TodoRepository에 QueryDSL을 정의한 TodoRepositoryQuery도 포함
public interface TodoRepository extends JpaRepository<Todo, Long>, TodoRepositoryQuery {
}
그러면 쿼리가 이렇게 join fetch되어서 N+1문제도 해결된채 잘 나오게 된다.
Hibernate:
/* select
todo
from
Todo todo
left join
fetch
todo.user
where
todo.id = ?1 */ select
t1_0.id,
t1_0.contents,
t1_0.created_at,
t1_0.modified_at,
t1_0.title,
t1_0.user_id,
u1_0.id,
u1_0.created_at,
u1_0.email,
u1_0.modified_at,
u1_0.nickname,
u1_0.password,
u1_0.user_role,
t1_0.weather
from
todos t1_0
left join
users u1_0
on u1_0.id=t1_0.user_id
where
t1_0.id=?