java - Spring 数据 JPA : Sorting and paging with joined tables

标签 java spring jpa spring-data spring-data-jpa

我有一个场景,我想对包含 3 个表的结果进行过滤、排序和分页。

目前我使用 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其中 customerNumber , itemNumbervalidDate同时用于过滤、排序和分页?

最佳答案

尝试这样的事情:

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);

更新

要按连接实体的字段添加排序,我们可以使用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")));

关于java - Spring 数据 JPA : Sorting and paging with joined tables,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45738336/

相关文章:

java - 从一个 Selenium session 到另一个 Selenium session 长期保存 Cookie 的最佳方法?

java - 制作一个二维的 10x2 数组,每个元素设置为字符串 "x"

mysql - 将 Grails 与 PostgreSQL 一起使用时出现 org.hibernate.StaleObjectStateException

java - 在任何查询之前 JPA 自动刷新

java - 如何扩展 JPA 实体以仅添加组合

java - 在 JPA 中使用数组进行 native 查询

java - 如何在 Java Character 类中表示空字符

java - 在方法中传递 2 个 json 格式的对象

java - 昨天日期的正则表达式模式,格式为 yyyymmdd

java - 如何从包含 url 的文件自动生成 REST 端点?