JPA 标准 API 不在代码简化和优化中
JPA Criteria API NOT IN Code Simplification and Optimization
我是 JPA 标准的新手 API。
2 个问题:
- 如何进一步简化此方法,第 3 条和第 4 条语句都需要 class 参数?
如何将 NOT IN
操作转换为 NOT EXISTS
以提高性能?
public List<Pilot> getPilotsExcept(final Integer... entityIds) {
final CriteriaBuilder critBuilder = em.getCriteriaBuilder();
final CriteriaQuery<Pilot> critQuery =
critBuilder.createQuery(getEntityClass());
final Root<Pilot> root = critQuery.from(getEntityClass()); // Why pass the class again?
critQuery.select(root).where(
critBuilder.not(root.get("id").in(Arrays.asList(entityIds))));
final TypedQuery<Pilot> typedQuery = em.createQuery(critQuery);
return typedQuery.getResultList();
}
Why pass the class again?
在 Criteria API 中,查询组件由对象表示。所以 select
子句和 from
子句由对象表示:
select
子句表示如下:
CriteriaQuery<Pilot> critQuery = critBuilder.createQuery(getEntityClass());
上一行的Pilot
class表示查询结果的return类型
另一方面,查询的 from
子句定义如下:
final Root<Pilot> root = critQuery.from(getEntityClass());
在此示例中,Root
和 CriteriaQuery
恰好具有相同的类型。但并非所有查询都是如此。在某些查询中,您可能希望 return 查询中的一个或多个属性(但不是查询中涉及的实体的所有属性)。在这些情况下,您在 CriteriaQuery
中指定的类型将不同于您在 Root
中使用的类型。例如,假设您的 Pilot
实体中有一个 name
属性,并且您只对 Pilot
实体的名称列表感兴趣。在这种情况下,您的 CriteriaQuery
将定义如下:
CrtieriaQuery<String> cq = cb.createQuery(String.class);
但在您的示例中,Root
的定义没有改变。
NOT EXISTS expression
为了能够将您的 not in
表达式转换为 not exists
形式,您必须使用 ID 制定子查询。以下是 JPA 规范的摘录:
An EXISTS expression is a predicate that is true only if the result of the subquery consists of one ormore values and that is false otherwise.
The syntax of an exists expression is
exists_expression::= [NOT] EXISTS (subquery)
Of course, this must be translated to the Criteria API, in which case the syntax will be
not(exists(subquery)).
下面是一个创建子查询的例子(伪代码):
Subquery<Integer> sq = critQuery.subquery(Integer.class);
Root<Pilot> pilot = sq.from(Pilot.class);
sq.select(pilot.<Integer>get("id"));
sq.where(<some_condition>);
我是 JPA 标准的新手 API。
2 个问题:
- 如何进一步简化此方法,第 3 条和第 4 条语句都需要 class 参数?
如何将
NOT IN
操作转换为NOT EXISTS
以提高性能?public List<Pilot> getPilotsExcept(final Integer... entityIds) { final CriteriaBuilder critBuilder = em.getCriteriaBuilder(); final CriteriaQuery<Pilot> critQuery = critBuilder.createQuery(getEntityClass()); final Root<Pilot> root = critQuery.from(getEntityClass()); // Why pass the class again? critQuery.select(root).where( critBuilder.not(root.get("id").in(Arrays.asList(entityIds)))); final TypedQuery<Pilot> typedQuery = em.createQuery(critQuery); return typedQuery.getResultList(); }
Why pass the class again?
在 Criteria API 中,查询组件由对象表示。所以 select
子句和 from
子句由对象表示:
select
子句表示如下:CriteriaQuery<Pilot> critQuery = critBuilder.createQuery(getEntityClass());
上一行的
Pilot
class表示查询结果的return类型另一方面,查询的
from
子句定义如下:final Root<Pilot> root = critQuery.from(getEntityClass());
在此示例中,Root
和 CriteriaQuery
恰好具有相同的类型。但并非所有查询都是如此。在某些查询中,您可能希望 return 查询中的一个或多个属性(但不是查询中涉及的实体的所有属性)。在这些情况下,您在 CriteriaQuery
中指定的类型将不同于您在 Root
中使用的类型。例如,假设您的 Pilot
实体中有一个 name
属性,并且您只对 Pilot
实体的名称列表感兴趣。在这种情况下,您的 CriteriaQuery
将定义如下:
CrtieriaQuery<String> cq = cb.createQuery(String.class);
但在您的示例中,Root
的定义没有改变。
NOT EXISTS expression
为了能够将您的 not in
表达式转换为 not exists
形式,您必须使用 ID 制定子查询。以下是 JPA 规范的摘录:
An EXISTS expression is a predicate that is true only if the result of the subquery consists of one ormore values and that is false otherwise. The syntax of an exists expression is
exists_expression::= [NOT] EXISTS (subquery) Of course, this must be translated to the Criteria API, in which case the syntax will be
not(exists(subquery)).
下面是一个创建子查询的例子(伪代码):
Subquery<Integer> sq = critQuery.subquery(Integer.class);
Root<Pilot> pilot = sq.from(Pilot.class);
sq.select(pilot.<Integer>get("id"));
sq.where(<some_condition>);