JPAリポジトリをテストしようとしています。これが私のクライアント/テストコードです:
_@Test
public void testFindBoitesByMultiFieldWithIdentifiantSet() {
BoiteDataOnDemand dod = new BoiteDataOnDemand();
Boite boite = dod.getSpecificBoite(0);
boite.setIdentifiant("theIdentifiant");
boiteRepository.save(boite);
assertEquals(10, Boite.countBoites());
BoiteQueryInfo boiteQueryInfo = new BoiteQueryInfo();
boiteQueryInfo.setIdentifiant("theIdentifiant");
List<Boite> boites = boiteRepository.findBoitesByMultiField(boiteQueryInfo, 1, 5, "identifiant", "desc");
assertEquals(1, boites.size());
}
_
リポジトリの方法は次のとおりです。
_@Override
public List<Boite> findBoitesByMultiField(BoiteQueryInfo boiteQueryInfo, Integer firstResult_, Integer maxResults_, String sort_, String order_) {
log.debug("findBoitesByMultiField");
final String identifiant = boiteQueryInfo.getIdentifiant();
final Date dateOuvertureFrom = boiteQueryInfo.getDateOuvertureFrom();
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Boite> c = criteriaBuilder.createQuery(Boite.class);
Root<Boite> boite = c.from(Boite.class);
List<Predicate> criteria = new ArrayList<Predicate>();
...
if (identifiant != null && !identifiant.trim().equals("")) {
ParameterExpression<String> parameter = criteriaBuilder.parameter(String.class, "identifiant");
Predicate condition = criteriaBuilder.like(boite.<String> get("identifiant"), parameter);
criteria.add(condition);
}
if (dateOuvertureFrom != null && dateOuvertureTo != null) {
ParameterExpression<Date> parameterDateOuvertureFrom = criteriaBuilder.parameter(Date.class, "dateOuvertureFrom");
ParameterExpression<Date> parameterDateOuvertureTo = criteriaBuilder.parameter(Date.class, "dateOuvertureTo");
Predicate condition = criteriaBuilder.between(boite.<Date> get("dateOuverture"), parameterDateOuvertureFrom, parameterDateOuvertureTo);
criteria.add(condition);
} else if (dateOuvertureFrom != null) {
ParameterExpression<Date> parameter = criteriaBuilder.parameter(Date.class, "dateOuvertureFrom");
Predicate condition = criteriaBuilder.greaterThanOrEqualTo(boite.<Date> get("dateOuverture"), parameter);
criteria.add(condition);
} else if (dateOuvertureTo != null) {
ParameterExpression<Date> parameter = criteriaBuilder.parameter(Date.class, "dateOuvertureTo");
Predicate condition = criteriaBuilder.lessThanOrEqualTo(boite.<Date> get("dateOuverture"), parameter);
criteria.add(condition);
}
...
if (order.equalsIgnoreCase("desc")) {
c.orderBy(criteriaBuilder.desc(boite.get(sort)));
} else {
c.orderBy(criteriaBuilder.asc(boite.get(sort)));
}
for (Predicate predicate : criteria) {
c.where(criteriaBuilder.and(predicate));
}
TypedQuery<Boite> q = em.createQuery(c);
if (identifiant != null && !identifiant.trim().equals("")) {
q.setParameter("identifiant", "%" + identifiant + "%");
}
if (dateOuvertureFrom != null && dateOuvertureTo != null) {
q.setParameter("dateOuvertureFrom", dateOuvertureFrom);
q.setParameter("dateOuvertureTo", dateOuvertureTo);
} else if (dateOuvertureFrom != null) {
q.setParameter("dateOuvertureFrom", dateOuvertureFrom);
} else if (dateOuvertureTo != null) {
q.setParameter("dateOuvertureTo", dateOuvertureTo);
}
...
return q.setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
}
_
ただし、テストは常にassertEquals(1, boites.size());
で失敗し、結果が返されないことを示します(つまり、(_Java.lang.AssertionError: expected:<1> but was:<0>
_)。
私はここで何かが間違っていると強く疑っています:
_for (Predicate predicate : criteria) {
c.where(criteriaBuilder.and(predicate));
}
_
しかし、基準を「そして」どのように「そして」するかはわかりません。
誰かアドバイスをいただけますか?
P.S.参考までに、BoiteDataOnDemand
はランダムな10行をboite
テーブルに挿入します。
編集:コードを編集して短くしました。
投稿の最後の部分にあるヒントから始めて、where
句の述語を追加する方法が正しくないことに同意します。
続行するには2つの方法があります。
最初の方法
述語の配列を使用する
List<Predicate> predicates = new ArrayList<Predicate>();
for (Key key : keys) {
predicates.add(criteriaBuilder.equal(root.get(key), value));
}
c.where(criteriaBuilder.and(predicates.toArray(new Predicate[] {})));
2番目の方法
ループ内の同じ述語を変更する
Predicate predicate = criteriaBuilder.conjunction();
for (Key key : keys) {
Predicate newPredicate = criteriaBuilder.equal(root.get(key), value);
predicate = criteriaBuilder.and(predicate, newPredicate);
}
c.where(predicate);
編集済み
コードサンプルをもう一度見てみると、Predicate
Sのリストがすでに正しい方法で作成されていることがわかります。これをcriteria
と呼んでいます。あなたはそれらを間違った方法で使用しているだけです。私の最初の例の最後の行を参照してください。
編集2
PredicateExpressionS
を使用して問題が発生したかどうかを確認するには、特に必要ではないので、一時的に削除してみてください。から最初の基準を変更します
if (identifiant != null && !identifiant.trim().equals("")) {
ParameterExpression<String> parameter = criteriaBuilder.parameter(String.class, "identifiant");
Predicate condition = criteriaBuilder.like(boite.<String> get("identifiant"), parameter);
criteria.add(condition);
}
に
if (identifiant != null && !identifiant.trim().equals("")) {
Predicate condition = criteriaBuilder.like(boite.get("identifiant"), "%" + identifiant + "%");
criteria.add(condition);
}
私のために働く完全な解決策は次のとおりです:
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Object[]> criteriaQuery = builder.createQuery(Object[].class);
Root<Eje> ejeRoot = criteriaQuery.from(Eje.class);
Root<FactorCritico> factorRoot = criteriaQuery.from(FactorCritico.class);
int factorParam = 2;
criteriaQuery.multiselect(ejeRoot,factorRoot);
List<Predicate> predicates = new ArrayList<>();
Predicate ejeJoinFactorCritico = builder.equal(ejeRoot.get("id"), factorRoot.get("eje"));
predicates.add(ejeJoinFactorCritico);
if (factorParam> 0){
Predicate factorFilter = builder.equal(factorRoot.get("id"), factorParam);
predicates.add(factorFilter);
}
criteriaQuery.where(builder.and(predicates.toArray(new Predicate[] {})));
Query<Object[]> query = session.createQuery(criteriaQuery);
List<Object[]> resultList = query.getResultList();
for(Object[] objects: resultList){
Eje eje = (Eje) objects[0];
System.out.println("eje: "+eje.getName());
FactorCritico factor= (FactorCritico) objects[1];
System.out.println("--> factor: "+factor.getName()+ ", eje: "+ factor.getEje().getName());
//System.out.println("eje, factor size = "+eje.getFactorCriticos());
}