2017-08-17 93 views
1

我有一個場景,我想過濾,排序和翻頁3個表參與的結果。Spring數據JPA:使用連接表進行排序和分頁

目前我使用Spring Data JPA的規範功能在單個實體上執行此操作:repository.findAll(specification, pageRequest)

這很好,但現在我有另一種場景,其中排序/篩選器屬性分佈在3個表,通過一對多關係連接。

這裏是我的情況:

@Entity 
public class CustomerEntity ... { 
    ... 

    @Column(nullable = false) 
    public String         customerNumber; 

    @OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, orphanRemoval = true) 
    public List<CustomerItemEntity> items; 
} 


@Entity 
public class CustomerItemEntity ... { 
    ... 

    @Column(nullable = false) 
    public String         itemNumber; 

    @ManyToOne(optional = false) 
    @JoinColumn(name = "customerId") 
    public CustomerEntity customer; 

    @OneToMany(mappedBy = "item", cascade = CascadeType.ALL, orphanRemoval = true) 
    public List<DocumentEntity> documents; 
} 


@Entity 
public class DocumentEntity ... { 
    ... 

    @Column(nullable = false) 
    public LocalDate         validDate; 

    @ManyToOne(optional = false) 
    @JoinColumn(name = "itemId") 
    public CustomerItemEntity item; 
} 

是否有使用PageRequestSpecification其中customerNumberitemNumbervalidDate用於過濾,同時排序和分頁的方式?

+0

不要忘記接受/ upvote幫助你的答案。 – Cepr0

回答

2

嘗試這樣:

Specification<CustomerEntity> joins = (customer, query, cb) -> { 
    // from CustomerEntity c 
    // join c.items i 
    Join<CustomerEntity, CustomerItemEntity> items = customer.join("items"); 

    // join i.documents d 
    Join<CustomerItemEntity, DocumentEntity> documents = items.join("documents"); 

    // // where c.customerNumber = ?1 and i.itemNumber = ?2 and d.validDate = ?3 
    return cb.and( 
      customer.equal(customer.get("customerNumber", customerNumber)), 
      items.equal(items.get("itemNumber", itemNumber)), 
      documents.equal(documents.get("validDate", validDate)) 
    ); 
}; 

// sort by c.customerNumber asc 
PageRequest pageRequest = new PageRequest(0, 2, new Sort(Sort.Direction.ASC, "customerNumber")); 

Page<CustomerEntity> customerPage = CustomerRepo.findAll(joins, pageRequest); 

但我不知道爲什麼你需要Specification在這裏?

可以做出相同的多個簡單:

@Query("select c from CustomerEntity c join c.items i join i.documents d where c.customerNumber = ?1 and i.itemNumber = ?2 and d.validDate = ?3") 
Page<CustomerEntity> getCustomers(String customerNumber, String itemNumber, LocaleDate validDate, Pageable pageable); 

但是,這一切沒有意義的,因爲你的三個實體具有順序一個一對多的關聯。在這種情況下,您可以只使用最後一種:where d.validDate = ?1。隨後的查詢方法變得更加容易:

@Query("select c from CustomerEntity c join c.items i join i.documents d where d.validDate = ?1") 
Page<CustomerEntity> getCustomers(LocaleDate validDate, Pageable pageable); 

UPDATE

要添加的加盟實體的字段排序我們可以使用queryorderBy方法:

Specification<CustomerEntity> joins = (customer, query, cb) -> { 

    Join<CustomerEntity, CustomerItemEntity> items = customer.join("items"); 
    Join<CustomerItemEntity, DocumentEntity> documents = items.join("documents"); 

    // Ascending order by 'Document.itemNumber' 
    query.orderBy(cb.asc(documents.get("itemNumber"))); 

    return cb.and( 
      customer.equal(customer.get("customerNumber", customerNumber)), 
      items.equal(items.get("itemNumber", itemNumber)), 
      documents.equal(documents.get("validDate", validDate)) 
    ); 
}; 

Page<CustomerEntity> customerPage = CustomerRepo.findAll(joins, new PageRequest(0, 2)); 

要按您可以將幾個參數傳遞給以逗號分隔的方法或List

query.orderBy(cb.asc(items.get("customerNumber")), cb.desc(documents.get("itemNumber"))); 
+0

謝謝,這對我很有用。順便說一句,我建立了規範,因爲過濾器是可選的。但是我還有一個問題:我怎樣才能按照連接的列之一進行排序?我不能只在PageRequest中定義這些屬性,因爲JPA告訴我'CustomerEntity'中沒有屬性。例如,你有一個想法如何通過'itemNumber'進行排序嗎? – Tobi

+0

@Tobi我更新我的答案(不要忘記如果它會幫助upvote它)... – Cepr0

+0

謝謝,但我有一個問題,提取正確的結果。當我過濾某個客戶,某個項目和具有特定有效日期的文檔時,我會在頁面對象中獲得正確數量的元素。但是,當我訪問作爲客戶實體的頁面內容時,我得到這一個客戶實體,但是它的所有項目和文檔,儘管我只能得到一個文檔的一個項目。你有一個想法如何提取正確的結果? – Tobi

相關問題