It is a different world altogether when you talk of persistence in the older
EJB specifications. The Entity Beans were truly heavyweight and the business
logic followed more of a procedural design rather than object-oriented one.
There were many reasons for this, one of them being the monolithic nature of the
EJBs themselves in the earlier specification. The specification had quite a few
limitations, for instance, starting with the configurations themselves was quite
tedious and persistence using the earlier specification was not an easy task
either. The only way you could use persistence for a session bean is by using a
'Session Façade'.
|
Similarly, the entity beans did not provide for inheritance, a factor that
would invariably exist amongst entities in a real life scenario database causing
problems in persisting such objects. The new specification eases persistence by
incorporating important changes such as support for inheritance. Other important
improvements are the use of dependency injection as a mechanism in place of JNDI
lookups.
By default, in EJB 3, the JNDI name is derived from the field type and the
setter methods and dependency injection encapsulates the look-up process.
Eliminating JNDI lookups not only simplifies session beans and message-driven
beans, but also reduces dependency on an application server's environment. It
also includes standardized OR mapping mechanism, and allows queries to be
created both statically and dynamically. In this article, we delve into a few of
these features that can ease the pain of implementing the business logic and
also persisting entities.
Sample Entity Bean
Let's first code a sample entity bean that represents an employee in an
organization. We'll make an EJB 3 Entity Bean, which will have most of the
properties defined using annotations. The code for the bean is as follows.
@Entity(access=AccessType.FIELD)
public class Employee {
private Long id;
private String name;
private String designation;
private String grade;
private Address address;
public Employee() {
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
...
}
The bean definition is simple and it represents an employee. However as per
the JSR-220, there are a lot more features at your disposal to harness the
improved design. For example, the Entity Bean supports inheritance, polymorphic
association and polymorphic queries also. As far as persistence is concerned, we
can define persistence properties right in the source code of the bean itself.
In our sample bean, the annotation '@Entity(access=AccessType. FIELD)' means
that the EJB container has to map the bean's field rather than the properties
for persistence. You can also map the properties for persistence by changing the
value of 'access' attribute to 'AccessType.PROPERTIES'. Similarly, you
can define
relationships for mappings of classes being used as a field in this class. For
example, our sample bean can define '@ManyToOne' annotation for 'Address'.
Address here is a separate class mapped to a relational table. These annotations
work in the same manner as the mappings defined using OR mapping documents if
using Hibernate (the HiBernate Mappings or HBMs). You can also avoid mappings
for a certain field/property by using the '@Transient' annotation. The
persisted field/properties can even be a Collection, or any of the following
collection interfaces, namely Set, List and Map. The entity is then created
using the good old 'new' operator. While this entity is not persistent by
default, the persistence in EJB 3 is handled by 'EntityManager' and related
interfaces in the persistence API.
The logical architecture of the new EJB 3 persistence API lets you manage persistence while preserving an object-oriented pattern |
The Entity Manager
This interface lies at the heart of the persistence API in EJB 3. The Entity
Manager instance in an application is always associated with a 'persistence
context' within which the entity instances and their lifecycle are managed.
The Entity Manager interface declares all the methods for interaction with the
persistence context. Other than this, the interface is used to create and remove
persistence entities, find entities using their primary key and query over the
entities. Here's a sample snippet of the use of EntityManager Interface.
@Stateless() // specifies a stateless entity
bean.
public class EmployeeSessionBean implements com.pcq.EmployeeSessionLocal {
@PersistenceContext EntityManager eManager;
public void makeIncentive(int empID, PayTransact pTrans){
Employee emp = eManager.find(Employee.class,int empID);
emp.getIncetives().add(amt);
pTrans.setTrans(emp);
}}
The '@PersistenceContext' annotation describes the dependency on the
EntityManager persistence context. The annotation has a 'PersistenceContextType'
element that defines the scope of dependency in the given application. The
element has two values Extended and Transaction-the former defines an extended
scope for the context (one that scopes beyond a transaction) while the latter
defines a transaction-scoped context and is the default value. We used the 'find
()' method here that locates a particular entity based on the primary key
specified. Other methods in the interface are 'persist (Object entity)' that
makes an entity instance persistent and managed, merge (T entity) that merges
the state of the given entity to the current persistence context. The remove
(Object entity) method removes the entity instance from the context, flush ( )
synchronizes the context to the database and refresh (Object entity) method
refreshes the state of the entity from the database by making all the changes in
the database that exist in the entity. All of these are to be invoked from
within a 'transaction-scoped' context otherwise the'javax.persistence.
TransactonRequieredException' is thrown.
The Query Interface
The query API is represented by this interface in EJB 3, and allows static and
dynamic queries and named parameter binding also. Lets look into how this
interface can be put into use in your code. The following method queries about
all employees of a particular designation.
public List getEmployeeNames(String desig){
return eManager.createQuery(“select a from Employee a where a.designation like
:d”)
.setParamter(“d”,desig)
.getResultList();
}
There are many ways of executing the same queries drilling down to specific
features supported by the interface. A named query executing the same results
can be implemented by using the '@NamedQuery' annotation as follows.
@NamedQuery{
name=”findNameOfEmployeesWithDesig”,
query=” select a from Employee a where a.designation like :d”
}
You can then use it in the 'getEmployeeName()' method as follows.
public List getEmployeeNames(String design){
return eManager.createQuery(findNameOfEmployeesWithDesig)
.setParamter(“d”,design)
.getResultList();
}
You can also specify the mapping of the result of a native SQL query in your
application. The persistence API defines the '@SetResultSetMapping' and '@SetResultSetMappings'
for this purpose. The former represents a single mapping whereas the latter can
be used for multiple mappings.
In conclusion
The API incorporates major changes in persistence as compared to the previous
versions allowing developers to write in an object-oriented pattern rather than
the 'transaction script' or procedural type code as mentioned before. While
frameworks such as Hibernate or JDO (Java Data Objects) are always available for
use, you can still find good usage for the new persistence API in EJB 3.