JPA Criteria Builder中的IN子句查询

56

如何编写标准构造器 API 查询以匹配以下给出的 JPQL 查询? 我正在使用 JPA 2.2

SELECT * 
FROM Employee e
WHERE e.Parent IN ('John','Raj')
ORDER BY e.Parent

在这里查看:包括IN在内的各种条件的大量示例:https://www.baeldung.com/hibernate-criteria-queries - Nestor Milyaev
5个回答

91

这个标准设置应该能够解决问题:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> q = cb.createQuery(Employee.class);


Root<Employee> root = q.from(Employee.class);
q.select(root);

List<String> parentList = Arrays.asList(new String[]{"John", "Raj"});

Expression<String> parentExpression = root.get(Employee_.Parent);
Predicate parentPredicate = parentExpression.in(parentList);
q.where(parentPredicate);
q.orderBy(cb.asc(root.get(Employee_.Parent));

q.getResultList();

我在这里使用了重载的 CriteriaQuery.where 方法,它接受一个 Predicate.. 在这种情况下是一个 in 谓词。


1
离题:感谢您编辑了我的一个答案;-) - GhostCat
3
你是说“Employee_”这个词从哪里来的? - madhairsilence
5
Employee_是Employee类的元模型。https://docs.oracle.com/javaee/6/tutorial/doc/gjivm.html - Martin WasGehtSieDasAn
1
请注意,自Java Persistence 2.0以来,在javax.persistence.criteria API中使用“Predicate”代替“Expression”,以解决Java泛型与varargs不兼容的问题。 - Zon

15

您也可以使用以下Criteria API In语句执行此操作:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);
Root<Employee> root = cq.from(Employee.class);
List<String> parentList = Arrays.asList("John", "Raj");
In<String> in = cb.in(root.get(Employee_parent));
parentList.forEach(p -> in.value(p));

return entityManager
        .createQuery(cq.select(root)
        .where(in).orderBy(cb.asc(root.get(Employee_.Parent)))
        .getResultList();

请查看我的Github,里面包含本例和几乎所有可能的条件示例。


10
List<String> parentList = Arrays.asList("John", "Raj");            
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
final CriteriaQuery<Employee> query = cb.createQuery(Employee.class);
final Root<Employee> employee = query.from(Employee.class);

query.select(employee).where(employee.get("Parent").in(parentList));

这应该可以正常工作。有关更多信息,请参阅Baeldung的文章。它非常有用。https://www.baeldung.com/jpa-criteria-api-in-expressions


我通常更喜欢类型安全的变量,因为这可以防止在重构属性名称后出现错误。 - Omnibyte

4

希望这对你有用。在该代码中,测试情况下Entry只有一个@Id列:

public static <Entry, Id> List<Entry> getByIds(List<Id> ids, Class<Entry> clazz, EntityManager entityManager) throws CustomDatabaseException
{
    List<Entry> entries;
    try
    {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<Entry> q = cb.createQuery(clazz);
        Root<Entry> root = q.from(clazz);
        EntityType<Entry> e = root.getModel();
        CriteriaQuery<Entry> all = q.where(root.get(e.getId(e.getIdType().getJavaType()).getName()).in(ids));

        TypedQuery<Entry> allQuery = entityManager.createQuery(all);
        entries = allQuery.getResultList();
    }
    catch (NoResultException nre)
    {
        entries = Collections.emptyList()
    }
    catch (Exception e)
    {
        throw new CustomDatabaseException(e);
    }
    return entries;
}

1

如果您需要再次使用Criteria API时不想费太多脑筋,您可以为Dao创建一个父包装类并在其中放置一个帮助方法

/**
  * An SQL "WHERE IN" expression alternative.
  *
  * @param inList List to search in.
  * @param pathToEntityField Path to a field in your entity object.
  * @return A ready predicate-condition to paste into CriteriaQuery.where().
  */
 @SuppressWarnings("unchecked")
 private Predicate in(List<?> inList, Expression pathToEntityField) {

   return pathToEntityField.in(inList);
}

使用 WHERE IN,然后像这样:
query.where(**in**(myList, root.get(MyTypedEntity_.id)));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接