4.4.4.4. Executing JPQL Queries

JPQL queries should be run through the Query interface. The reference to it may be obtained from the current EntityManager instance by calling createQuery() method. If the query is supposed to be used to load entities, we recommend calling createQuery() and passing the result type as parameter. This will create a TypedQuery instance.

The methods of Query mainly correspond to the methods of a standard javax.persistence.Query interface. Let us have a look at the differences.

  • setParameter() – sets a value to a query parameter. If the value is an entity instance, implicitly converts the instance into its identifier. For example:

    Customer customer = ...;
    TypedQuery<Order> query = entityManager.createQuery(
        "select o from sales$Order o where o.customer.id = ?1", Order.class);
    query.setParameter(1, customer);

    Note that the actual entity is passed as parameter while comparison in the query is done using identifier.

    A variant of the method with implicitConversions = false does not do such conversion.

  • setView(), addView() – are similar to the EntityManager methods with the same names – they define a view, used to load data with the current query and do not affect the view of the entire EntityManager.

  • getDelegate() – returns an instance of javax.persistence.Query, provided by the ORM implementation.

When a request is run through Query changes in the current persistent context are ignored, i.e. the query just runs in DB. If the results of selection are the instances already contained in persistent context, then the query result will contain instances from context and not the ones read from DB. The following test fragment should clarify this:

TypedQuery<User> query;
List<User> list;

query = em.createQuery("select u from sec$User u where u.name = ?1", User.class);
query.setParameter(1, "testUser");
list = query.getResultList();
assertEquals(1, list.size());
User user = list.get(0);

user.setName("newName");

query = em.createQuery("select u from sec$User u where u.name = ?1", User.class);
query.setParameter(1, "testUser");
list = query.getResultList();
assertEquals(1, list.size());
User user1 = list.get(0);

assertTrue(user1 == user);

This behavior is controlled by openjpa.IgnoreChanges=true, parameter defined in persistence.xml file of the cuba base project. It is possible to change this parameter in your project by including it in the project's own persistence.xml.

The queries, which change data (update, delete) cause flush of the data from the current persistent context to the database prior to execution. In other words, ORM first synchronizes the states of entities in the persistent context and DB, and only after that runs the modifying query. We recommend to run such queries in an unchanged persistent context in order to prevent implicit actions by the ORM, which may have negative impact on performance.