假设我有两个实体User和Task,每个用户可以有一个任务。
我面临的问题是,如果用户表中有一条记录的电子邮件以a
开头,而任务表中根本没有记录。
以下代码段将不返回任何记录,尽管我希望用户的邮件以a
开头。
示例中的UserRepository扩展了QuerydslPredicateExecutor。
userRepository.findAll(
QUser.user.email.startsWith("a")
.or(QUser.user.task.text.contains("something"))
)
如果检查日志,则Hibernate将使用user.task_id=task.id
创建交叉联接,作为where子句的一部分。如果用户未分配任务,则这种类型的加入会自动丢弃其邮件以a
开头的用户。
在存储库的findAll方法中是否有一种方法可以强制使用左联接而不是交叉联接?
我知道我可以使用JPAQuery
来做到这一点,但随后我将不得不重新实现分页功能...
JPAQuery query = new JPAQuery(entityManager);
query
.from(QUser.user)
.leftJoin(QTask.task)
// ...
QUser qUser = QUser.user;
QTask qTask = QTask.task;
JPQL<UserEntity> userJpqlQuery = JPAExpressions.selectFrom(qUser)
.leftjoin(qUser.task, qTask)
.where(qUser.email...., qTask.text...);
userRepository.findAll(qUser.in(userJpqlQuery));
在上面的代码中,我使用了
Querydsl,它是CriteriaBuilder的替代方法,并且类型安全。然后,我创建了一个子查询以进行所需的选择,并返回与该子查询匹配的所有用户。
最后,休眠应生成如下内容:select * from User qUser0 where qUser0.id.in( select qUser1.id from User qUser1 left join Task qTask0 on qUser1.taskId = qTask0.id where ... );