Criteria API组合AND/OR

Lau*_*ens 4 java jpa java-ee criteria-api

我正在努力使用Criteria API创建查询.以下SQL查询返回我需要的结果:

SELECT * FROM MODEL WHERE MANUFACTURER_ID = 1 AND SHORTNAME LIKE '%SF%' OR LONGNAME LIKE '%SF%';
Run Code Online (Sandbox Code Playgroud)

我使用条件API编写了以下代码:

public List<Model> findAllByManufacturer(Manufacturer manufacturer,
        String pattern) {
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Model> cq = cb.createQuery(Model.class);
    Root<Model> m = cq.from(Model.class);
    cq.select(m);
    Join<Model, Manufacturer> mf = m.join("manufacturer");
    Predicate p = cb.equal(mf.get("id"), manufacturer.getId());
    p = cb.and(cb.like(cb.upper(m.<String>get("shortName")),
            pattern.toUpperCase()));
    p = cb.or(cb.equal(cb.upper(m.<String>get("longName")),
            pattern.toUpperCase()));
    cq.where(p);
    return em.createQuery(cq).getResultList();
}
Run Code Online (Sandbox Code Playgroud)

当我从逻辑上思考它时,它应该工作:

Predicate p = cb.equal(mf.get("id"), manufacturer.getId());
Run Code Online (Sandbox Code Playgroud)

WHERE MANUFACTURER_ID = 1

p = cb.and(cb.like(cb.upper(m.<String>get("shortName")),
                pattern.toUpperCase()));
Run Code Online (Sandbox Code Playgroud)

和SHORTNAME一样'%SF%'

p = cb.or(cb.equal(cb.upper(m.<String>get("longName")),
                pattern.toUpperCase()));
Run Code Online (Sandbox Code Playgroud)

或者LONGNAME喜欢'%SF%'

查询运行正常,因为我没有收到任何错误,它只是没有返回任何结果.任何关于我出错的线索都非常感谢!

JB *_*zet 7

你检查过生成的SQL了吗?

您正在构建谓词并将其分配给p,但随后您将创建另一个谓词并将其分配给同一p变量.

我认为它应该是:

Predicate predicateOnManufacturerId = cb.equal(mf.get("id"), 
                                               manufacturer.getId());
Predicate predicateOnShortName = cb.like(cb.upper(m.<String>get("shortName")),
                                         pattern.toUpperCase()));
Predicate predicateOnLongName = cb.equal(cb.upper(m.<String>get("longName")),
                                         pattern.toUpperCase()));
Predicate p = cb.or(cb.and(predicateOnManufacturerId, 
                           predicateOnShortName),
                    predicateOnLongName);
cq.where(p);
Run Code Online (Sandbox Code Playgroud)

另外,为什么不使用实体的元模型:

Join<Model, Manufacturer> mf = m.join(Model_.manufacturer);
... cb.equal(mf.get(Manufacturer_.id);
...
Run Code Online (Sandbox Code Playgroud)

它更加类型安全,您可以在编译时检测不正确的查询,而不是运行时.