web-dev-qa-db-ja.com

Spring Data JPA:結合されたテーブルを使用した並べ替えとページング

3つのテーブルが参加する結果をフィルタリング、並べ替え、ページングするシナリオがあります。

現時点では、Spring Data JPAの仕様機能を使用して、単一のエンティティrepository.findAll(specification, pageRequest)でそれを実行しています。

これはうまく機能しますが、ソート/フィルター属性が1対多の関係で接続された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を使用する方法はありますか?ここで、customerNumberitemNumber、およびvalidDateは、フィルタリング、並べ替え、およびページングに使用されます。同時?

5
Tobi

次のようなものを試してください。

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

ただし、3つのエンティティには連続した1対多の関連付けがあるため、これはすべて意味がありません。この場合、3つの条件の代わりに、最後の1つだけを使用できます。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);

[〜#〜]更新[〜#〜]

結合されたエンティティのフィールドによる並べ替えを追加するには、orderByqueryメソッドを使用できます。

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")));
4
Cepr0