October 31, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Standard Persistence Properties in JPA 2, Page 2

  • October 27, 2010
  • By KL Nitin
  • Send Email »
  • More Articles »

Standard Persistence Properties

The persistence.xml file, the configuration file for JPA applications has definitions for a set of persistence units. Each persistence unit defines one or more managed entities that the EntityManager instance of an application can manage. Each persistence unit provides a set of properties for configuring the data source. Along with all the necessary connection details, the persistence unit also specifies the JPA provider. It is possible to have different persistence providers for different persistence units.

With JPA 1, each provider defined its own set of JDBC properties and it was very difficult to manage them with different providers across different persistence units. JPA 2 eliminates this problem by standardizing these properties. The following code snippet shows a sample persistence.xml file that defines the JDBC properties:

<persistence-unit name="JPAProject" 
transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<!--Entity Classes -->
<class>com.infosys.demo.Item</class>
<class>com.infosys.demo.Employee</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/JPA 2" />
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.user" value="root" />
<property name="javax.persistence.jdbc.password" value="infosys"/>
<property name="javax.persistence.jdbc.show_sql" value="true" />
</properties>
</persistence-unit>

The <persistence-unit> element holds the configuration information about the data source. The name attribute specifies the name with which this persistence unit is identified, which will be provided while creating the EntityManagerFactory instance. The persistence unit specifies the provider (EclipseLink in this case) and the various Entity classes that need to be managed within the persistence context. It also specifies the various JDBC properties such as the driver name, database URL, username, password, and so on.

Additional JPQL Features

JPQL was one of the important factors in the success of JPA1.x. One of the most significant developments that JPA 2 brought in was in its querying model. More object-oriented querying was made possible in JPA 2 by criteria queries (explained in detail in Querying in JPA 2: Typesafe and Object Oriented). With the Query interface, JPA 2 introduced the TypedQuery interface, which extends the Query interface and makes JPQL queries more type safe. With this interface, the query can be made to return a specific type. For example, in the following code snippet the query object is of TypedQuery type and its return type is Employee:

EntityManagerFactory emf = 
Persistence.createEntityManagerFactory("JPAProject");
EntityManager em = emf.createEntityManager();

TypedQuery<Employee> query =
em.createQuery("SELECT e FROM Employee e", Employee.class);
List<Employee> r = query.getResultList();

In the above code snippet, a TypedQuery instance query is created for a SELECT query. At the time of creating the query instance we are sure that the query would return only Employee instances, which is specified in the second argument of the createQuery method.

The following additional capabilities were added to JPQL in JPA 2:

  • A collection object can become an argument to IN expression
  • Support for non-polymorphic queries
  • Provision for timestamp literals
  • CASE statement in JPQL
  • Querying ordered lists

1. A Collection Object Can Become an Argument to IN Expression

The IN expression used in the WHERE clause of the JPQL query now can be supplied with a Collection object as the parameter. In the following example, the JPQL query selects the Bankdetails of customers whose names are listed in the names object.

List<String> names = new ArrayList<String>(); 
names.add("Nitin");
names.add("Mahalakshmi");
names.add("Nirmal");
List<Bankdetails> result =
em.createQuery("SELECT x FROM Bankdetails x WHERE x.name IN :namesList").setParameter("namesList", names).getResultList();

2. Support for Non-polymorphic Queries

JPA 1.x supported polymorphic queries, where the query fired in terms of the parent class would yield all its sub classes also. But there are scenarios where the developer is interested only in one sub class and not in obtaining the result of the other sub class. In this scenario, non-polymorphic queries come in very handy.

In the example below, CreditCard and BankAccount are the two sub classes of the Bankdetails class and the implementation uses the one-table-per-class hierarchy strategy in JPA. If the developer is interested in obtaining only CreditCard objects, the TYPE function can be used to specify the type that needs to be obtained.

List<Bankdetails> result = (List<Bankdetails>) em.createQuery(

 


"SELECT x FROM Bankdetails x WHERE TYPE(x) = CreditCard").getResultList();

3. Provision for Timestamp Literals

JPA 2 supports timestamp literals in JPQL queries. The Employee entity class defines a java.util.Date attribute, which is decorated with @Temporal. The Temporal types are used for properties of an Entity class that are basically time based. The supported Temporal types are javax.sql.Data, javax.sql.Time, javax.sql.Timestamp, java.util.Date and java.util.Calendar.

@Entity 
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
@Temporal(TemporalType.TIMESTAMP)
private Date time;
// Some other code
}

The following query searches for all the Employee instances whose time attribute is greater than a specified value.

List<Employee> result = (List< Employee >) 
em.createQuery("SELECT e from Employee e WHERE e.time > '2008-06-01 10:00:01.0-09:00'").getResultList();

4. CASE Statement in JPQL

JPA 2 supports CASE expressions in JPQL queries. CASE statements are very helpful in a situation where bulk updates on the entities need to be performed based on a specific condition. CASE statements can also be used in a SELECT clause, which will help in reporting the queries in a much better manner. The general syntax for defining a CASE expression is as follows:

CASE { 
WHEN <conditional_expression> THEN <Scalar_Expression>
WHEN <conditional_expression> THEN <Scalar_Expression>
….
}
ELSE <Scalar_Expression> END

CASE expressions for UPDATE are used in case of bulk updates, and updates to entities can be performed by calling the executeUpdate method on the query instance.

em.createQuery("UPDATE Employee e SET e.age = CASE e.id WHEN 1 THEN 23 WHEN 2 THEN 24 ELSE 25 END").executeUpdate();

In the above code snippet the Employee instances are updated with a new age property based on the id property (i.e. the age is set to 23 if the id is 1 or set to 24 if the id is 2, and the default age of 25 is set for those Employee instances whose id is not specified).

CASE expressions in SELECT are used mainly for reporting purpose and returning better query results. In this case, a CASE expression will be used with a SELECT clause of the JPQL query.

List<Object[]> result3 = em.createQuery( 
"SELECT x.name, CASE WHEN TYPE(x) = CreditCard THEN 'CREDITCARD' "
+ " WHEN TYPE(x) = BankAccount THEN 'BANKACCOUNT' "
+ " ELSE 'BA' END"
+ " FROM Bankdetails x where x.balance > 20000", Object[].class)
.getResultList();

In this example, the CASE expression is used in the SELECT clause to obtain the Bankdetails of those customers whose balance is greater than 20000.

5. Querying the Ordered List

JPA 2 specifies a new annotation @OrderColumn for ManyToMany and OneToMany relationships by adding a new index column, which need not be mapped in the Entity Class. In this example the Employee has a OneToMany relationship with the Dealer class and the indexno column of the Dealer table maintains the order of insertion (index).

@Entity 
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;

// Other code
@OneToMany(cascade = CascadeType.ALL, mappedBy="empId")
@OrderColumn(name="indexno")
private List<Dealer> dealerCollection;
}

The following query queries for the first three Dealers associated with an Employee whose name is specified. The INDEX function can be used to index the Dealer instances in the query.

List<Dealer> res = 
em.createQuery("SELECT d from Employee e JOIN e.dealerCollection d"
+ " WHERE e.empName='Maha' AND INDEX(d) < 3").getResultList();

Conclusion

In this article, I explained with code snippets the new enhancements made to the EntityManager, EntityManagerFactory and Query API, the standardized properties defined in the persistence.xml file and certain advancements made to JPQL. The code snippets provided are all compatible with the JPA 2 reference implementation EclipseLink.

Acknowledgements

I would like to sincerely thank Mr. Subrahmanya (SV, VP, ECOM Research Group, E&R) for his constant encouragement and Ms. Sangeetha S for providing the ideas, guidance, and valuable comments as well as for kindly reviewing this article.


Tags: Java EE 6, JPA, Java Persistence

Originally published on http://www.developer.com.

Page 2 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel