スプリングブーツはこちら。複雑なクエリを実装するコンテキストで使用される場合、JpaRepositories
とSpecifications
を囲み、いくつかのアイテムで「木々の森」を見るのに苦労しています。
Specification
の標準的な例は次のとおりです。
_public class PersonSpecification implements Specification<Person> {
private Person filter;
public PersonSpecification(Person filter) {
super();
this.filter = filter;
}
public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> cq,
CriteriaBuilder cb) {
Predicate p = cb.disjunction();
if (filter.getName() != null) {
p.getExpressions()
.add(cb.equal(root.get("name"), filter.getName()));
}
if (filter.getSurname() != null && filter.getAge() != null) {
p.getExpressions().add(
cb.and(cb.equal(root.get("surname"), filter.getSurname()),
cb.equal(root.get("age"), filter.getAge())));
}
return p;
}
}
_
このtoPredicate(...)
メソッドでは、_Root<Person>
_とCriteriaQuery
は何を表していますか?最も重要なことは、それはsoundseachに1つのSpecification
implを作成する必要があるように、各仕様が1つに変換され、たった1つの述語...例えば、「Smeeb」という姓で25歳以上のすべての人を見つけたい場合、_LastnameMatchingSpecification<Person>
_と_AgeGreaterThanSpecification<Person>
_。誰かがこれを確認または明確化できますか?!
これも最初は私にとって大変でしたが、今では簡単に動的クエリを作成し、テーブルごとに1つの仕様を作成しています(高度な検索が必要な場合)
これらのオブジェクトを次のように考えてください:
-
常にリストから始めて、最後にニーズに基づいてAND/OR条件でそれらを要約します。
public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
List<Predicate> predicates = new ArrayList<>();
if(filter.getName() != null) {
predicates.add(cb.equal(root.get("name"), filter.getName());
}
if(filter.getSurname() != null) {
predicates.add(cb.equal(root.get("surname"), filter.getSurname());
}
if(filter.getAge() != null) {
predicates.add(cb.equal(root.get("age"), filter.getAge());
}
if(predicates.isEmpty()){
predicates.add(cb.equal(root.get("id"), -1);
/*
I like to add this because without it if no criteria is specified then
everything is returned. Because that's how queries work without where
clauses. However, if my user doesn't provide any criteria I want to
say no results found.
*/
}
return query.where(cb.and(predicates.toArray(new Predicate[0])))
.distinct(true).orderBy(cb.desc(root.get("name")).getRestriction();
}
これで、ユーザーはこれら3つのフィールドの任意の組み合わせをここに渡すことができ、このロジックはクエリを動的に構築してそれらの条件を含めます。
例えばname = Johnおよびsurname = Doeおよびage = 41またはname = Johnおよびage = 41またはname = Johnなど。
最後に、文字列を検索するときは、cb.equalではなくcb.likeを使用することをお勧めします。これにより、%での部分検索がユーザーまたはフロントエンドシステムによって渡されるようになります。
Cb.likeはデフォルトで大文字と小文字を区別しないことに注意してください。次のようなcb.lowerまたはcb.upperと組み合わせて使用する必要があります。
predicates.add(cb.like(cb.lower(root.get("name"), filter.getName().toLowercase());
お役に立てれば !