比方说,我有两个实体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)
// ...
答案 0 :(得分:0)
我不确定是否可以这样做,因为findAll实现是为我们生成的。但是,我们可以在findAll方法中传递谓词,这将有助于处理您遇到的问题。
您可以尝试执行以下操作:
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 ...
);