CriteriaBuilder.createQuery和EntityManager.createQuery有什么区别?

问题描述

假设我有代码,例如:

EntityManager em = ...;
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Pet> cq = cb.createquery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.select(pet);
TypedQuery<Pet> q = em.createquery(cq);
List<Pet> allPets = q.getResultList();

能否请您解释一下为什么我们使用两种createquery()方法,它们之间有什么区别?

解决方法

CriteriaBuilder#createQuery(Class<T> resultClass)创建CriteriaQuery<T>

EntityManager#createQuery(CriteriaQuery<T> criteriaQuery)创建TypedQuery<T>

TL; DR:

这两种类型不是彼此替代的,它们具有不同的用途:

CriteriaQuery<T>用于以编程方式定义查询,而不是手动编写查询,并且TypedQuery<T>用于避免强制转换,而在使用Query时必须执行此操作。您甚至可以将两者结合使用,我将向您展示-方法。


现在,让我们详细了解一下。

TypedQuery<T>

JPA用QueryTypedQuery<T>StoredProcedureQuery实例(均来自javax.persistence包,而后两个扩展{{1} }。

使用Query的简单示例如下:

Query

请注意,Query query = em.createQuery("your select query.."); //you write query SomeType result = (SomeType) query.getSingleResult(); //cast needed List<SomeType> resultList = (List<SomeType>) query.getResultList(); //cast needed API方法将返回Query或原始类型(无特殊类型)Object实例,您必须将其强制转换为期望的类型。

另一方面,

ListTypedQuery<T>的不同之处在于,在创建查询时您提供了期望的返回值的类,并且跳过了强制转换部分,如下所示:

Query

重要的要点是,在所有这些情况下,您都必须手动编写HQL或JPQL查询,以构造相应的TypedQuery<SomeType> typedQuery = em.createQuery("your select query.."); SomeType result = typedQuery.getSingleResult(); //<-- no cast needed. List<SomeType> result = typedQuery.getResultList(); //<-- no cast needed. 实例,然后,您将调用相应的方法。

Query

JPA Specification 2.2

JPA Criteria API用于通过构建基于对象的查询定义对象来定义查询,而不是使用Java Persistence查询语言的基于字符串的方法。

CriteriaQuery<T>在概念上与CriteriaQuery相同(您构建用于从数据库获取数据或从数据库获取数据的查询),它是定义JPQL的另一种方法/ HQL查询。

Query的主要目的是提供一种 programmatic type-safe 方式来定义与平台无关的查询。因此,您无需以编程方式构造查询,而无需手动编写HQL / JPQL查询,如下所示:

CriteriaQuery<T>

回答您的最后一个问题-哪种方法可以访问数据库?

在上述所有情况下,调用CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<SomeType> cq = cb.createQuery(SomeType.class); Root<SomeType> root = cq.from(SomeType.class); //programmatically adding criterias and/or some filter clauses to your query cq.select(root); cq.orderBy(cb.desc(root.get("id"))); //passing cq to entityManager or session object TypedQuery<SomeType> typedQuery = entityManager.createQuery(cq); List<SomeType> list = typedQuery.getResultList(); (或其子对象)对象的方法时,实际查询都会命中数据库。在我们的示例中,这些是:

Query

记住两个步骤:

  1. 您定义/构造查询对象(使用query.getSingleResult(); query.getResultList(); typedQuery.getSingleResult(); typedQuery.getResultList(); HQLJPQL);
  2. 您在该对象上调用API方法,这些方法实际上查询数据库。