【问题标题】:Spring Data JPA repository with specification, pagination and criteria fetch-joinSpring Data JPA 存储库,具有规范、分页和条件获取连接
【发布时间】:2017-01-29 14:10:11
【问题描述】:

我正在为实体列表实现搜索/过滤服务,使用具有规范和分页功能的 Spring Data JPA 存储库。我正在尝试减少查询数量(n+1 问题)并使用标准获取机制获取嵌套数据。

我有两个实体类:

@Entity
@Table(name = "delegations")
public class Delegation {

    @Id
    @GeneratedValue(strategy = IDENTITY)
    private Long id;

    @ManyToOne
    private Customer customer;

    // more fields, getters, setters, business logic...

}

@Entity
@Table(name = "customers")
public class Customer {

    @Id
    @GeneratedValue(strategy = IDENTITY)
    private Long id;

    // more fields, getters, setters, business logic...
}

DTO 过滤器类:

public class DelegationFilter {

    private String customerName;

    // more filters, getters, setters...
}

及搜索/过滤服务:

public class DelegationService {
    public Page<Delegation> findAll(DelegationFilter filter, Pageable page) {
        Specifications<Delegation> spec = Specifications.where(
                customerLike(filter.getCustomerName())
        );
        return delegationRepository.findAll(spec, page);
    }

    public List<Delegation> findAll(DelegationFilter filter) {
        Specifications<Delegation> spec = Specifications.where(
                customerLike(filter.getCustomerName())
        );
        return delegationRepository.findAll(spec);
    }

    private Specification<Delegation> customerLike(String customerName) {
        return (root, query, cb) -> {
            Join<Delegation,Customer> join = (Join) root.fetch(Delegation_.customer);
            return cb.like(cb.lower(join.get(Customer_.name)), addWildCards(customerName.toLowerCase()));
        };
    }

    private static String addWildCards(String param) {
        return '%' + param + '%';
    }
}

问题

当我打电话给findAll(DelegationFilter filter, Pageable page) 时,我遇到了异常:

org.springframework.dao.InvalidDataAccessApiUsageException: 
org.hibernate.QueryException: query specified join fetching, but the owner 
of the fetched association was not present in the select list

有没有办法解决这个问题?

findAll(DelegationFilter filter)(没有分页的方法)就像魅力一样......仅使用join(没有fetch)也可以正常工作(即使有分页)

我知道 JPQL 有解决方案: Spring-Data FETCH JOIN with Paging is not working 但我想坚持使用标准 api...

我正在使用 Spring Boot 1.4(spring 4.3.2,spring-data-jpa 1.10.2)和 Hibernate 5.0.9

【问题讨论】:

    标签: java spring hibernate spring-data spring-data-jpa


    【解决方案1】:

    我遇到了同样的问题,我找到了解决方法 (source)。

    您可以在运行时检查查询的返回类型,如果它是Long(计数查询返回的类型),则您加入,否则您获取。在您的代码中,它将如下所示:

    ...
    private Specification<Delegation> customerLike(String customerName) {
        return (root, query, cb) -> {
            if (query.getResultType() != Long.class && query.getResultType() != long.class) {
              Join<Delegation,Customer> join = (Join) root.fetch(Delegation_.customer);
            } else {
              Join<Delegation,Customer> join = root.join(Delegation_.customer);
            }
            return cb.like(cb.lower(join.get(Customer_.name)), addWildCards(customerName.toLowerCase()));
        };
    }
    ...
    

    我知道它不是很干净,但这是我在 ATM 上找到的唯一解决方案。

    【讨论】:

    • 看起来很难看 :) 但似乎是解决方案...谢谢 :)
    • 我不敢相信这不是一个更常用的解决方案,我找了很久。我遇到的所有其他解决方案都需要单独的 Count Query / JPQL,从不使用自定义规范。 +100 非常感谢您
    • 有趣的是 Spring Data 的新版本中是否有任何更新?
    猜你喜欢
    • 2015-06-03
    • 2017-05-12
    • 2013-07-27
    • 1970-01-01
    • 2018-11-17
    • 2021-10-16
    • 2021-11-09
    • 2021-04-20
    • 1970-01-01
    相关资源
    最近更新 更多