【问题标题】:How to set a Collection/List to a named parameter of a JPA criteria query?如何将集合/列表设置为 JPA 条件查询的命名参数?
【发布时间】:2013-06-10 15:37:26
【问题描述】:

可以将单个命名参数设置为 JPA 条件查询,如下所示。在这种情况下,参数的类型为Long

public StateTable find(Long id)
{
    CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
    CriteriaQuery<StateTable> criteriaQuery = criteriaBuilder.createQuery(StateTable.class);
    Metamodel metamodel=entityManager.getMetamodel();
    EntityType<StateTable> entityType = metamodel.entity(StateTable.class);
    Root<StateTable> root = criteriaQuery.from(entityType);

    ParameterExpression<Long> parameterExpression=criteriaBuilder.parameter(Long.class);
    criteriaQuery.where(criteriaBuilder.equal(root.get(StateTable_.stateId), parameterExpression));

    TypedQuery<StateTable> typedQuery = entityManager.createQuery(criteriaQuery);
    return typedQuery.setParameter(parameterExpression, id).getSingleResult();
}

方法中的这个查询返回我正在处理的StateTable(只是说状态)实体的单个对象,并对应于以下 JPQL 查询。

entityManager.createQuery("select s from StateTable s where s.stateId=:id")
             .setParameter("id", id)
             .getSingleResult();

我需要找到多个对应于通过java.util.List&lt;Long&gt; 提供的ID 列表的行。以下是条件查询的不完整版本。

public List<StateTable> find(List<Long> ids)
{
    CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
    CriteriaQuery<StateTable> criteriaQuery=criteriaBuilder.createQuery(StateTable.class);
    Metamodel metamodel=entityManager.getMetamodel();
    EntityType<StateTable> entityType = metamodel.entity(StateTable.class);
    Root<StateTable> root = criteriaQuery.from(entityType);

    ParameterExpression<Long> parameterExpression = criteriaBuilder.parameter(Long.class);
    criteriaQuery.where(criteriaBuilder.in(root.get(StateTable_.stateId)).value(parameterExpression));

    TypedQuery<StateTable> typedQuery = entityManager.createQuery(criteriaQuery);
    return typedQuery.setParameter(parameterExpression, 1L).getResultList();
}

它使用 in() 查询,但我让它只返回一行,因为我不知道是否可以将 id 列表设置为 ParameterExpression

简而言之,这个条件查询应该对应于下面的 JPQL 查询。

entityManager.createQuery("from StateTable where stateId in(:id)")
             .setParameter("id", ids)
             .getResultList();

有没有办法按照指定将List&lt;Long&gt; 设置为ParameterExpression

【问题讨论】:

    标签: jpa jpa-2.0 criteria criteria-api


    【解决方案1】:

    以下方法对我有用。

    public List<StateTable> find(List<Long> ids)
    {
        CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
        CriteriaQuery<StateTable> criteriaQuery=criteriaBuilder.createQuery(StateTable.class);
        Metamodel metamodel=entityManager.getMetamodel();
        EntityType<StateTable> entityType = metamodel.entity(StateTable.class);
        Root<StateTable> root = criteriaQuery.from(entityType);
    
        //ParameterExpression<Long> parameterExpression = criteriaBuilder.parameter(Long.class);
        //criteriaQuery.where(criteriaBuilder.in(root.get(StateTable_.stateId)).value(parameterExpression));
        criteriaQuery.where(root.get(StateTable_.stateId).in(ids));
    
        TypedQuery<StateTable> typedQuery = entityManager.createQuery(criteriaQuery);
        return typedQuery.getResultList();
    }
    

    我刚刚添加了以下行。

    criteriaQuery.where(root.get(StateTable_.stateId).in(ids));
    

    从问题中查询的不完整版本中删除上述注释行。

    【讨论】:

    • 这确实意味着服务器端查询缓存受到了负面影响。我想知道在使用 ParameterExpression 时是否有办法做到这一点?
    • 到目前为止,即使使用 JPA 2.1 标准批量更新和删除,我也只看到了这个。
    • 我不认为这是数组绑定。如果你查看实际的SQL,你会看到参数仍然是一个一个设置,比如in (?, ?, ?),而不是一个集合(in (?)),所以downvote。我认为可能的是 Hibernate 的 setParameterList(),但不是 JPA 的一部分。
    【解决方案2】:

    我最近正在调查同样的事情,并找到了一个不会影响服务器端查询缓存的解决方案。 Using a ParameterExpression as part of the In clause

    请注意,这应该是对 Jannik Jochem 在此页面答案下的评论的回应;但是,我的代表很少,所以如果你有足够的代表,请随时删除这篇文章并添加评论。

    【讨论】:

      猜你喜欢
      • 2010-10-08
      • 2011-12-07
      • 1970-01-01
      • 1970-01-01
      • 2011-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-29
      相关资源
      最近更新 更多