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
を使用する方法はありますか?ここで、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);
ただし、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);
[〜#〜]更新[〜#〜]
結合されたエンティティのフィールドによる並べ替えを追加するには、orderBy
のquery
メソッドを使用できます。
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")));