2016-09-21 142 views
1

我使用具有规范和分页功能的Spring Data JPA存储库实现了实体列表的搜索/过滤服务。我试图减少查询数量(n + 1问题)并使用标准提取机制获取嵌套数据。Spring Data JPA repository with specification,pagination and criteria fetch-join

我有两个实体类:

@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 1.4启动(春4.3.2,弹簧数据的JPA 1.10.2)和Hibernate 5.0.9

回答

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())); 
    }; 
} 
... 

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

+0

看起来很丑:)但看起来像解决方案...谢谢:) –

相关问题