2016-09-21 107 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

看起來很醜:)但看起來像解決方案...謝謝:) –