[英]Spring Data JPA: Sorting and paging with joined tables
我有一个场景,我想对 3 个表参与的结果进行过滤、排序和分页。
目前,我使用 Spring Data JPA 的 Specification 功能在单个实体上执行此操作: 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;
}
有没有办法使用PageRequest
和Specification
,其中customerNumber
、 itemNumber
和validDate
用于同时过滤、排序和分页?
尝试这样的事情:
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);
更新
要按连接实体的字段添加排序,我们可以使用query
orderBy
方法:
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")));
我发现您可以使用可以使用自定义查询创建的连接别名来按 OneToMany 列的内容排序。 在存储库中,我的代码是:
@Query("select p from Person p join p.roles r")
Page<Person> search(Pageable pageable);
所以我能够使用以下方法进行排序:
r.role
从控制器传递使用:
@PageableDefault(size = 15, sort = "r.role") Pageable pageable
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.