This tutorial guides you how to use named queries in Java Persistence API (JPA). Basically you execute a query in JPA like this:

String jpql = "SELECT u from User u";

Query query = entityManager.createQuery(jpql);

List<User> result = query.getResultList();

for (User user : result) {
	System.out.println(user);
}
This approach is perfect for simple applications that have only a small number of queries. What if your application becomes larger with tens or hundreds queries scattered in many classes? Then imagine the nightmare of maintaining such a large number of queries in your fat code base. Therefore, JPA provides the concept of named queries to make programmer’s life easier: you can group related queries in one place (usually in model classes) and refer them in your code by their names - hence the term named queries. Below is an example:

String queryName = "User.findAll";
Query query = entityManager.createNamedQuery(queryName);

List<User> listUsers = query.getResultList();
Here, the query name “User.findAll” refers to a query which can be stored in a relevant domain model class like this:

@Entity
@Table(name = "USERS")

@NamedQueries({
	
	@NamedQuery(name = "User.findAll", query = "SELECT u FROM User u ORDER BY u.fullname")
	
})
public class User {
	private Integer id;
	private String fullname;
	private String email;
	private String password;

	...
	...
}
As you can see, there are two annotations are used for named query:@NamedQueries annotation consists of a set of @NameQuery annotations with each define a specific JPQL query:

@NamedQueries({
	
	@NamedQuery(name = "User.findAll", query = "SELECT u FROM User u ORDER BY u.fullname")
	
})
To specify multiple named queries, separate the @NameQuery annotations by commas:

@NamedQueries({
	
	@NamedQuery(name = "User.findAll", query = "SELECT u FROM User u ORDER BY u.fullname"),
	@NamedQuery(name = "User.count", query = "SELECT COUNT(*) FROM User u"),
	@NamedQuery(name = "User.removeAll", query = "DELETE FROM User u")
	
})
 

The following code illustrates how to execute the named query User.count above:

Query query = entityManager.createNamedQuery("User.count");
long count = (long) query.getSingleResult();
 

And the following example executes the named query User.removeAll above:

entityManager.getTransaction().begin();

Query query = entityManager.createNamedQuery("User.removeAll");
query.executeUpdate();

entityManager.getTransaction().commit();


 

Using Named Query with Parameters:

If your query consists of parameters, you can use the setParameter(name, value) or setParameter(position, value) to set values for the parameters dynamically.

For example, consider the following named query that contains one parameter named email

@NamedQuery(name = "User.findByEmail", query = "SELECT u FROM User u WHERE u.email = :email")
 

The following code sets parameter for this query and executes it (set values for parameters by their names):

String queryName = "User.findByEmail";
String email = "tom@gmail.com";

Query query = entityManager.createNamedQuery(queryName);
query.setParameter("email", email);

User user = (User) query.getSingleResult();
 

And this named query has two positional parameters:

@NamedQuery(name = "User.checkLogin", query = "SELECT u FROM User u WHERE u.email = ?1 AND password = ?2")
 

And the following code sets values for the positional parameters above:

String queryName = "User.checkLogin";
String email = "tom@gmail.com";
String pass = "tomsecret1";

Query query = entityManager.createNamedQuery(queryName);
query.setParameter(1, email);
query.setParameter(2, pass);

User user = (User) query.getSingleResult();
It’s recommended to use name-based parameters for the readability of your code.

 

Named Queries Stored in XML:

Besides embedding named queries in model classes, you can also store named queries in a separate XML file. For example, create queries.xml file under META-INFdirectory with the following content:

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="2.0" xmlns="http://java.sun.com/xml/ns/persistence/orm"
	 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm 
 		http://java.sun.com/xml/ns/persistence/orm_2_0.xsd "
>
	<named-query name="WhoUsingGmail">
		<query>SELECT u FROM User u WHERE u.email LIKE '%gmail%'</query>
	</named-query>
	
	<named-query name="WhoNotSetPassword">
		<query>SELECT u FROM User u WHERE u.password is null</query>
	</named-query>

</entity-mappings>
 

And tell JPA to load this XML file in the persistence.xml file like this:

…
<persistence-unit name="UsersDB">
	
	<mapping-file>META-INF/queries.xml</mapping-file>
	
	<properties>
	
		...
	</properties>	
</persistence-unit>
…
Then you can use named queries in your code normally. This configuration is more flexible as we don’t have to re-compile the code when making changes to the queries.

 

References:

Query Javadocs

             EntityManager Javadocs


About the Author:

is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.



Add comment

   


Comments 

#2Rangappa Patel2021-09-20 10:08
Hi Nam, Hope you are doing well.
Can you please give me a query for below scenario.
a.Add a “Named Query” called ‘findByCdPrice’ which should show all the CDs which have a price greater than the given price.
b.The above query should also show the ‘No. of CDs’ as per the price criteria
Quote
#1Ednilton Curt Rauh2021-06-08 21:11
Thanks Brother nice tutorial, congratz from Brazil.
Quote