2017-08-17 49 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

相关问题