通过用户定义的动态 where 子句条件在 JPA 中创建高级搜索

Create advanced search in JPA through user defined dynamic where clause conditions

我想创建一个搜索,用户可以在其中定义 where 子句条件。如果用户在搜索表单中输入参数,则该参数将包含在 WHERE 子句中。如果参数留空,则从 where 子句中省略。如果整个表格是空白的,查询应该 returns 一个 SELECT ALL 和整个 table。以这种方式,用户输入的参数越多,查询就越精确。

我正在尝试下面的代码,但这似乎需要输入参数,并且 returns 只有当实际数据与指定的所有谓词匹配时才会产生结果。看起来 Predicates 被包含在数组中,即使它们是 NULL 和空的?要么,要么我在写这篇文章时遗漏了一些非常明显的东西。

我的问题是:

1) 如果搜索表单留空,谓词是否会被排除在数组之外?

2) 如果是,查询不会默认为 SELECT ALL 吗? [query.from(Contacts.class)]?

我看到了一个类似的问题,但并没有真正告诉我如何实现上述目标,因为看起来我的代码逻辑是正确的。

JPA where clause any

提前感谢您的指导!

public ListDataModel<Contacts> qSearchContacts(String firstName, String surName, Integer countryid, Integer companyId) {

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Contacts> query = cb.createQuery(Contacts.class);
    Root<Contacts> cont = query.from(Contacts.class);
    query.select(cont);

    List<Predicate> predicateList = new ArrayList<Predicate>();
    Predicate firstnamePredicate, surnamePredicate, countryPredicate, companyPredicate;

    if ((firstName != null) && (!(firstName.isEmpty()))) {
        firstnamePredicate = cb.like(cb.upper(cont.<String>get("firstName")), "%" + firstName.toUpperCase() + "%");
        predicateList.add(firstnamePredicate);
    }


    if ((surName != null) && (!(surName.isEmpty()))) {
        surnamePredicate = cb.like(cb.upper(cont.<String>get("surName")), "%" + surName.toUpperCase() + "%");
        predicateList.add(surnamePredicate);

     }

    if (countryid != null) {
        Join<Contacts, Country> country = cont.join("country");
        countryPredicate = cb.equal(country.<Integer>get("countryid"), countryid);
        predicateList.add(countryPredicate);
    } 
    }

    if (companyId != null) {
        Join<Contacts, Company> company = cont.join("company");
        companyPredicate = cb.equal(company.<Integer>get("companyId"), companyId);
        predicateList.add(companyPredicate);
    }

    Predicate[] predicateArray = new Predicate[predicateList.size()];
    predicateList.toArray(predicateArray);
    query.where(predicateArray);
    ListDataModel<Contacts> contactResultList = new ListDataModel<Contacts>(em.createQuery(query).getResultList());

    return contactResultList;
}

我解决了这个问题。上面的代码似乎在所有情况下都创建了谓词,并且没有明确的条件可以从数组列表中排除谓词或在不存在谓词的情况下执行 SELECT ALL。我使用 TypedQuery 对象显式地重写了每个参数的代码。现在这会导致所需的行为。没有谓词导致 SELECT ALL。如果每个谓词不为 null 且不为空,则仅作为 WHERE 子句条件包括在内。希望这可以帮助。

public ListDataModel<Contacts> qSearchContacts(String firstName, String surName, Integer countryid, Integer companyId) {

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Contacts> query = cb.createQuery(Contacts.class);
    Root<Contacts> cont = query.from(Contacts.class);
    query.select(cont);

    // Join<Contacts, Country> country = cont.join("country", JoinType.LEFT);
    List<Predicate> predicateList = new ArrayList<Predicate>();

    if ((firstName != null) && (!(firstName.isEmpty()))) {
        ParameterExpression<String> p
                = cb.parameter(String.class, "firstName");
        predicateList.add(cb.like(cb.upper(cont.<String>get("firstName")), "%" + firstName.toUpperCase() + "%"));

    }

    if ((surName != null) && (!(surName.isEmpty()))) {
        ParameterExpression<String> p
                = cb.parameter(String.class, "surName");
        predicateList.add(cb.like(cb.upper(cont.<String>get("surName")), "%" + surName.toUpperCase() + "%"));

    }

    if ((countryid != null) && (countryid != 0)) {
        Join<Contacts, Country> country = cont.join("country");
        ParameterExpression<Integer> ci
                = cb.parameter(Integer.class, "countryid");
        predicateList.add(cb.equal(country.get("countryid"), ci));
    }

    if ((companyId != null) && (companyId != 0)) {
        Join<Contacts, Company> company = cont.join("company");
        ParameterExpression<Integer> co
                = cb.parameter(Integer.class, "companyId");
        predicateList.add(cb.equal(company.get("companyId"), co));
    }

    if (predicateList.size() == 0) {
        query.select(cont);
    } else {
        if (predicateList.size() == 1) {
            query.where(predicateList.get(0));
        } else {
            query.where(cb.and(predicateList.toArray(new Predicate[0])));
        }
    }

    TypedQuery<Contacts> tq = em.createQuery(query);
    if (firstName != null) {
        tq.setParameter("firstName", firstName);
    }
    if (surName != null) {
        tq.setParameter("surName", surName);
    }

    if ((countryid != null) && (countryid != 0)) {
        tq.setParameter("countryid", countryid);
    }

    if((companyId != null) && (companyId != 0)) {
        tq.setParameter("companyId", companyId);
    }

    ListDataModel<Contacts> contactsResultList = new ListDataModel<Contacts>(tq.getResultList());
    return contactsResultList;

}
}