JPA Criteria builder IN 子句查询

Posted

技术标签:

【中文标题】JPA Criteria builder IN 子句查询【英文标题】:JPA Criteria builder IN clause query 【发布时间】:2017-07-20 17:14:21 【问题描述】:

如何为以下给定的 JPQL 查询编写标准构建器 api 查询? 我正在使用JPA 2.2

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

【问题讨论】:

在这里查看:各种标准的大量示例,包括 IN:baeldung.com/hibernate-criteria-queries 【参考方案1】:

这个标准设置应该可以解决问题:

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 谓词。

【讨论】:

非常感谢!! Offtopic:感谢您编辑我的一个答案 ;-) 你从哪里得到 Employee_ Employee_是Employee类docs.oracle.com/javaee/6/tutorial/doc/gjivm.html的元模型 请注意,由于在 javax.persistence.criteria API 中使用 Java Persistence 2.0 Predicate 而不是 Expression,以解决 Java 泛型与可变参数不兼容的事实。【参考方案2】:

您也可以使用 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 了解这个以及几乎所有可能的标准示例。

【讨论】:

【参考方案3】:

当您需要使用 Criteria API 再次执行此操作时,不要伤脑筋 - 您可以为您的 Dao 创建一个 父包装类 并在其中放置一个 hepler 方法

/**
  * 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)));

【讨论】:

【参考方案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;

【讨论】:

【参考方案5】:
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

【讨论】:

我通常更喜欢类型安全的变体,因为这样可以防止重构属性名称后出错。

以上是关于JPA Criteria builder IN 子句查询的主要内容,如果未能解决你的问题,请参考以下文章

JPA Criteria Query distinct

JPA Criteria API IN 表达式 参数列表

jpa criteria-api:加入子选择

在 JPA Criteria API 的子查询中使用 ORDER BY 的替代方法是啥?

JPA 如何获取 Criteria API 中使用的参数标记的数量?

hibernate.jpa.criteria.BasicPathUsageException:无法加入基本类型的属性