有人可以向我解释为什么Spring使用其specification功能在可分页LEFT JOIN
上添加Order
检查吗?
情况是:
我想使用Spring规范来生成用于过滤数据的动态查询,并通过分页来限制数据。该查询在UserEntity
和UserGroupEntity
之间,并且我想始终在每次查询中都提取UserGroupEntity
,因此我为COUNT
和数据查询添加了一个检查块。如果查询是查询COUNT
,则使用Join
对象,否则使用Fetch
对象。
public static Specification<UserEntity> filtered(final String searchTerm) {
return new Specification<UserEntity>() {
@SuppressWarnings("unchecked")
@Override
public Predicate toPredicate(Root<UserEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
Join<UserEntity, UserGroupEntity> joinUserGroup = null;
if (QueryHelper.isQueryCount(query)) {
joinUserGroup = root.join("userGroup");
} else {
Fetch<UserEntity, UserGroupEntity> fetchUserGroup = root.fetch("userGroup");
joinUserGroup = (Join<UserEntity, UserGroupEntity>) fetchUserGroup;
}
if (searchTerm != null) {
List<Predicate> predicates = new ArrayList<Predicate>();
predicates.add(cb.like(root.get("lowerUsername").as(String.class), "%" + searchTerm.toLowerCase() + "%"));
predicates.add(cb.like(root.get("lowerEmail").as(String.class), "%" + searchTerm.toLowerCase() + "%"));
predicates.add(cb.like(joinUserGroup.get("lowerName").as(String.class), "%" + searchTerm.toLowerCase() + "%"));
cb.or(predicates.toArray(new Predicate[predicates.size()]));
}
return null;
}
};
}
这就是我在UserService
上调用规范的方式:
Order order = new Order(Direction.ASC, "lowerEmail");
Page<UserEntity> pages = userRepository.findAll(filtered(searchTerm), new PageRequest(page, size, new Sort(order)));
当我使用UserEntity
列添加订单时,查询很好。这是生成的HQL:
select generatedAlias0 from com.example.entity.UserEntity as generatedAlias0
inner join fetch generatedAlias0.userGroup as generatedAlias1
order by generatedAlias0.lowerEmail asc
但是当我使用联接的实体中的列作为userGroup.lowerName
进行排序时,查询变得奇怪(因为我不知道为什么)。通过使用该列,Spring在查询中添加了更多LEFT JOIN
并使其如下所示:
select generatedAlias0 from com.example.entity.UserEntity as generatedAlias0
left join generatedAlias0.userGroup as generatedAlias1
inner join fetch generatedAlias0.userGroup as generatedAlias2
order by generatedAlias1.lowerName asc
[当我遇到Github上的spring-data-JPA代码时,我发现从specification
到criteria
的转换是在方法getQuery()
中完成的。此方法从类toOrders()
调用其他方法QueryUtils
以应用排序顺序。方法toOrders()
最后调用方法getOrCreateJoin()
或isAlreadyFetched()
,它们将检查先前的联接属性(我在规范中创建的联接属性)userGroup
,但是由于联接类型不是LEFT JOIN
,因此Spring添加了在我的查询中使用LEFT JOIN
进一步加入。
private static Join<?, ?> getOrCreateJoin(From<?, ?> from, String attribute) {
for (Join<?, ?> join : from.getJoins()) {
boolean sameName = join.getAttribute().getName().equals(attribute);
if (sameName && join.getJoinType().equals(JoinType.LEFT)) {
return join;
}
}
return from.join(attribute, JoinType.LEFT);
}
这就是我在spring-data-jpa
代码CMIIW上的搜索结果。我仍然不了解JoinType.LEFT
的目的是什么。您的解释对我(和我们)将非常有帮助。
现在,我认为我将使用自定义存储库来使用JPQL生成动态查询,直到我理解使用LEFT JOIN
和specification
生成带有附加pageable
的查询的原因。
我遇到了同样的问题,并在https://stackoverflow.com/a/43965633/7280115中找到了解决方案和答案。您可以检查它是否也适合您]