hibernate - 正确使用JPA标准API,谓词以及CriteriaQuery的where方法

标签 hibernate jpa jpa-2.0 criteria-api

我正在尝试测试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.仅供引用,BoiteDataOnDemandboite表中随机插入10行。

编辑:编辑代码以使其更短。

最佳答案

从帖子最后部分的提示开始,我同意您为where子句添加谓词的方式不正确。

我看到了两种处理方式:

第一种方式

使用谓词数组

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[] {})));

第二种方式

在循环中修改相同的谓词
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);
}

关于hibernate - 正确使用JPA标准API,谓词以及CriteriaQuery的where方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12244799/

相关文章:

java - Spring Restful 编辑 - 保存更改的最佳实践是什么

java - Hibernate注解(金字塔结构-同表)

Java - 日期格式

java - 在查询中纳入特定检查的最佳实践 - 需要专家意见

jakarta-ee - 内部字段出现 OptimisticLockingException

java - 是否有更有效的使用 EntityManager 的习惯用法?

java - 是否可以将方法传递给条件限制?

java - JPA 选择多个字段

JPA EclipseLink : Persisting detached entity does not throw any error

java - 由 SQL 连接查询映射的 JPA 实体