Webcam Chat QuickBooks Advice international calling cards international phone cards
JavaBeat Certifications Certifications Kits Articles Tutorials Tips QNA Book Store Interview Questions SCJP 1.5 SCJP 1.6 SCWCD 5.0 SCBCD 5.0 SCEA SCJA Feeds
Kaspersky Anti-Virus 2011
Submit Your Blog Feedback Request Article Print Email

Introduction to Java Persistence API(JPA)

Author : Raja
Topic : ejb3 jpa 
Pages :
Hibernate Books | Spring Books | JSF Books | Java Books

The Query API

One of the disadvantage of locating the entity objects using the EntityManager.find() and EntityManager.getReference() methods is, we cannot specify any powerful search criteria for searching the entity objects. All we can provide is the primary key to request for a particular object. Another fact is the class name of entity must be known. The Query API that comes with JPA is powerful in the sense more additional criteria can be specified in the run-time during executing the query.

EntityManager serves as factory classes for getting a reference to the Query objects. The query string that we specify for locating entity objects is called Java Persistent Query Language (JPQL). The current version of the JPQL is 1.0 and it is more robust flexible and object-oriented than SQL. The persistence engine will parse the query string, transform the JPQL to the native SQL before executing it.

Types of Queries

Queries can be classified into two different types depending upon how actually the query string is defined. One is the static query (Named Query) and the other one, the Dynamic Query.

Static Query

A static query (or a named query) is one which is defined statically with the help of annotation (or XML) before the entity class. A name is usually given to the query definition so that other components in the same persistent unit can refer the query using the same. For example,


	@NamedQuery(name = ” MobileEntity.findAll” query = “SELECT M FROM MOBILEENTITY”)
	@Entity
	class MobileEntity{
	}

A named query (with a name ‘Mobile.findAll’) has been defined and this query can be referenced later in the code through its name, like this.


	Query findAllQuery = entityManager.createNamedQuery(“MobileEntity.findAll”);
	// Execute the query.

Note that the code is referring the query by its name (‘Mobile.findAll’) by calling the createNamedQuery() method. Also, since these named queries are statically defined, during deployment time itself, the persistent engine may parse and translate the JPQL into native SQL, cache them, thereby yielding better performance.

Multiple named queries can be logically defined with the help of @NamedQueries, like this,


	@NamedQueries( {
	@NamedQuery(name = “Mobile.selectAllQuery” query = “SELECT M FROM MOBILEENTITY”),

		@NamedQuery(name = “Mobile.deleteAllQuery” query = “DELETE M FROM MOBILEENTITY”)
	} )
[The @NamedQueries is very similar like @NamedQuery, but can accept multiple @NamedQuery objects, The definition of the @NamedQueries looks like this,

	@interface NamedQuries{
		NamedQuery[] value;
	}
The way to specify arrayed elements with the definition of an annotation is by using {}. So was defined for the @NamedQueries( {…} ) and since the property called ‘value’ is the default property name for annotation, there is no need to explicitly mention the property name in the annotation definition. Following also works well which explicitly defines the property name ‘value’ for the annotation @NamedQueries.

	@NamedQueries(value = { …. } )

Dynamic Queries

Dynamic Queries are nothing but whose query strings are provided at run-time. All calls to EntityManager.createQuery(queryString) are actually creating dynamic query objects. By defining query objects in this way, we lose the efficiency and from the performance point of view, the query execution may be slow as the persistence engine has to do all the parsing and validation stuffs, along with mapping the JPQL to the SQL at the run-time.

Following code creates a dynamic query object on the fly.


	String queryString = …… // Obtained during run-time.
	Query dynaQuery = entityManager.createQuery(queryString);
Static Queries will be a better choice if the scenario for which the query to be executed is well known in advance.

Query Operations

Subsequent topics cover how to work with the query API for locating the entity objects, named and the positional support for Query objects and Paging Query Results for performance.

Single Result

The following code shows how to execute a query that returns a single entity object (assuming that a table called MobileEntity with field’s model, manufacturer and imei are available in the database).


	Query singleSelectQuery = entityManager.createQuery(
	“SELECT M FROM MOBILEENTITY WHERE M.IMEI = ‘ABC-123’”);
	MobileEntity mobileObj = singleSelectQuery.getSingleResult();

The query string that’s defined inside the createQuery() method is the Java Persistence Query Language. The Java Persistent Query Language (JPQL) resembles more like a SQL. The query statement is a simple select statement that is used to select a particular mobile object with imeiNo ‘ABC-123’. M represents a named instance row, which can be used to directly refer the fields in the corresponding table.

A call to getSingleResult() will execute the query and returns a single row that matches the search criteria in the query string. If the match wasn’t successful, then the getSingleResult() will return an EntityNotFoundException. Also, if more than one matches occur during query execution (this may not happen in our case, since imeiNo is a primary key), a run-time NonUniqueResultException will be thrown.

Multiple Results

Query.getResultList() will execute a query and may return a List object containing multiple entity instances. The following code demonstrates the same.


	Query multipleSelect = entityManager.createQuery(“SELECT M FROM MOBILE”);
	List mobiles =
	(List)multipleSelect.getResultList();

The type-cast (List) is necessary as the getResultList() method will return a non-parameterized List object. If only one mobile object is found as a result of executing the query, then this method may simple return a list with size 1. Also note that, getResultList() method can only execute on select statements as opposed to UPDATE or DELETE statements. If any statement other than SELECT statement is passed on to the method, then an IllegalStateException will be thrown at the run-time.

Working with parameters

To reuse and to execute the query more efficiently with different set of values, one can depend on the parameter support (positional and named) offered by the JPA. These techniques resembles the one we had for the java.sql.PreparedStatement where one can prepare the statement object once and can execute the query with different set of parameter values again and again.

The positional parameter is used to bind the parameter value in terms of positional index and it is denoted by ?index within the query string. Similarly the named parameter is used to substitute the parameter value which is specified in terms of :name.

Following examples will clarify the above concepts,


	String selectQuery =
	“SELECT M FROM MOBILE WHERE M.MODEL = ?1 and M.MANUFACTURER = ?2”;
	Query selectQuery = entityManager.createQuery(selectQuery);

	selectQuery.setParameter(1, model);
	selectQuery.setParameter(2, manufacturer);

The above code illustrates the positional parameter support, during query execution,?1 and ?2 will be replaced with the values specified for model and manufacturer.

For named parameter, the parameter can be given with some meaningful name prefixed with :, like the below code,


	String selectQuery = “SELECT M FROM MOBILE WHERE M.MODEL = :modelName and M.MANUFACTURER = :manufacturer”;
	Query selectQuery = entityManager.createQuery(selectQuery);

	selectQuery.setParameter(“modelName”, model);
	selectQuery.setParameter(“manufacturer”, manufacturer);

It is not that only dynamic queries can be benefited with positional and named parameters. Even for statically defined queries, the same is applicable. We can embed : or ? even in the static query definitions also,


	@NamedQuery(
	name =
	“Mobile.findByModel” query = “SELECT M FROM MOBILEENTITY WHERE M.MODEL  = :modelName
	)
	…

And later in code,


	Query namedQuery = entityManager.createNamedQuery(“Mobile.findByModel”);
	namedQuery.setParameter(“modelName”, model);

Paging Query Results

Imagine that a select query is returning larger number of record entities, it may not be advisable to show the entire set of results to the end-user as it may eat performance. The following two methods can be used in tandem to solve this kind of performance issue.

Assume that we have 1000 mobile entities in our database and we wish to show only 100 objects in an application that displays them in a nice tabular view. In the following code, before calling the getResultList(), which will return all the mobile objects in the database, the query object is well configured with setMaxResults(maxResults) method (the number of maximum entity objects that will be returned) setFirstPosition(position) method (which tells starting position of the pointer is made to point to).


	int maxRecords = 10;
	int startPosition = 0;
	String queryString = “SELECT M FROM MOBILEENTITY”;

	while(true){

		Query selectQuery = entityManager.createQuery(queryString);
		selectQuery.setMaxResults(maxRecords);
		selectQuery.setFirstResult(startPosition);
		List mobiles = entityManager.getResultList(queryString);

		if (mobiles.isEmpty()){
			break;
		}

	//Process the mobile entities.
	process(mobiles);
	entityManager.clear();

	startPosition = startPosition + mobiles.size();
	}

The above code loops through all the 100 objects in the database in a more efficient way. Also note that the EntityManager.clear() method is called every time, to clear (or to detach) the mobile objects which will make the EntityManager less burdened in terms of managing the mobile objects.

Flushing Query objects

JPA provides two modes of flushing query objects namely AUTO and COMMIT (which are defined in FlushModeType Enumeration). If the AUTO mode is set on the Query object which is the default one, then any changes made to entity objects will be reflected the very next time when a select query is made. That means that the persistence engine must make sure to update all the states of the entity objects which will affect the results of a SELECT query.

The AUTO flush mode can be set explicitly on the Query by calling setFlushMode().


	queryObject.setFlushMode(FlushModeType.AUTO);

When the flush mode is set to COMMIT, then the persistence engine, may only update all the state of the entities during the database COMMIT. The dirty changes applied to entity objects and then querying for the results of the entities may be unspecified.


	queryObject.setFlushMode(FlushModeType.COMMIT);
[The method setFlushMode(FlushModeType) is available in both EntityManager and Query interface. If the EntityManager has been configured with setFlushMode(FlushModeType.AUTO) and the Query object has been called with setFlushMode(FlushModeType.COMMIT), then the preference will always goes to the Query object.]

Recommended Books

Submit Your Blog Feedback Request Article Print Email

Java / J2EE Tutorials

Spring Framework

Hibernate Framework

JSF Framework

Struts Framework

Java Server Pages(JSP)

Servlets

Java / J2EE Design Patterns

SCJP

SCEA


JavaBeat Website (2004-2009), India
javabeat | advertise | about us | useful resources
Copyright (2004 - 2009), JavaBeat