Never use QueryDsl Predicate Executor
til
I like queries that the compiler can check. querydsl gives me a middle ground between raw SQL and an object-relational mapper (ORM), which maps database records to application objects.
Spring Data JPA provides QueryDslPredicateExecutor for queries built from Predicate instances in querydsl, but it limits the control I want over joins, ordering, and result limits.
@Repository
interface UserRepository : JpaRepository<User, Long>, QueryDslPredicateExecutor<User>Suppose we want a page of users sorted by name in descending order. This findAll call takes a predicate, or query condition, and a Pageable instance. The example does not specify the ordering:
import org.springframework.data.querydsl.QuerydslPredicateExecutor
@Service
class UserService(
private val userRepository: UserRepository
) {
fun findUsers(pageable: Pageable): Page<User> {
// no ordering!
val predicate = QUser.user.name.isNotNull
return userRepository.findAll(predicate, pageable)
}
}Using Querydsl directly gives us control over the query while keeping the compiler's checks:
import com.querydsl.jpa.impl.JPAQueryFactory
data class Paginated<T>(
val data: List<T>,
val next: Long?
)
@Repository
class UserRepository(
private val entityManager: EntityManager
) {
private val queryFactory = JPAQueryFactory(entityManager)
fun findUsers(pageSize: Int, next: Long?): Paginated<User> {
val query = queryFactory
.selectFrom(QUser.user)
.orderBy(QUser.user.name.desc())
next?.let {
queryFactory
.selectFrom(QUser.user)
.where(QUser.user.id.eq(it))
.fetchOne()?.let { cursor ->
query.where(QUser.user.name.lt(cursor.name))
}
}
return Paginated(
items=query.limit((pageSize + 1).toLong()).fetch().take(pageSize),
next=items.get(pageSize - 1)?.id
)
}
}