Skip to content
Advertisement

What is the difference between CriteriaBuilder.createQuery and EntityManager.createQuery?

Let’s say I have the code, like:

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();

Can some please explain why we are using two createQuery() methods and what is the difference between them?

Advertisement

Answer

CriteriaBuilder#createQuery(Class<T> resultClass) creates CriteriaQuery<T>
and
EntityManager#createQuery(CriteriaQuery<T> criteriaQuery) creates TypedQuery<T>.

TL;DR:

These two types are not the alternatives of each other, they rather serve the different purposes:

CriteriaQuery<T> is used to programmatically define query, instead of writing it manually, and TypedQuery<T> is used to avoid casting which you have to do when using Query. You can even use both in conjunction and I will show you – how.


Now, let’s see this in a bit more details.

TypedQuery<T>

JPA represents query with Query, TypedQuery<T> or StoredProcedureQuery instance (all from javax.persistence package, and latter two extend Query).

A simple example of using Query would look like this:

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

Note, that Query API methods return either Object or raw type (without specialized type) List instances, which you have to cast to your expected type.

TypedQuery<T>, on the other hand, differs from Query in a way, that you provide the class of your expected return value when creating the query, and you skip the casting part, like this:

TypedQuery<SomeType> typedQuery = em.createQuery("your select query..");
SomeType result = typedQuery.getSingleResult(); //<-- no cast needed.
List<SomeType> result = typedQuery.getResultList(); //<-- no cast needed.

Important point here is, that in all these cases, you have to write HQL or JPQL query manually in order to construct corresponding Query instance, on which, you will, afterwards, invoke corresponding method(s).

CriteriaQuery<T>

JPA Specification 2.2:

The JPA Criteria API is used to define queries through the construction of object-based query definition objects, rather than use of the string-based approach of the Java Persistence query language.

CriteriaQuery is conceptually same thing as Query(you build the Query which you use to get data from/to database) and it is an alternative way of defining JPQL/HQL queries.

The main purpose of CriteriaQuery<T> is to provide a programmatic and type-safe way to define a platform-independent queries. So, instead of manually writing HQL/JPQL queries, you construct the query programmatically, like this:

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();

Answering your final question – which methods hits the database?:

In all above cases, actual query hits the database when you invoke methods of Query (or its child) objects. In our examples, these are:

query.getSingleResult();
query.getResultList();
typedQuery.getSingleResult();
typedQuery.getResultList();

Remember two steps:

  1. You define/construct the query object (either with HQL, JPQL or CriteriaQuery<T>);
  2. You invoke the API methods on that object, which actually query the database.
User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement