具有规范的可分页弹簧,按连接列在订单上添加更多LEFT JOIN

问题描述 投票:4回答:1

有人可以向我解释为什么Spring使用其specification功能在可分页LEFT JOIN上添加Order检查吗?

情况是:

我想使用Spring规范来生成用于过滤数据的动态查询,并通过分页来限制数据。该查询在UserEntityUserGroupEntity之间,并且我想始终在每次查询中都提取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代码时,我发现从specificationcriteria的转换是在方法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 JOINspecification生成带有附加pageable的查询的原因。

spring jpa spring-data-jpa specifications
1个回答
0
投票

我遇到了同样的问题,并在https://stackoverflow.com/a/43965633/7280115中找到了解决方案和答案。您可以检查它是否也适合您]

© www.soinside.com 2019 - 2024. All rights reserved.