12
Data Access Pattern

WHAT’S IN THIS CHAPTER?            

  • Discussion regarding the origins of the data access pattern
  • Examination of the related data transfer object
  • How the DAO and factory pattern work together
  • An introduction to the JPA and ORM
  • A simple implementation of the DAO
  • An improved implementation using generics
  • A discussion regarding the role of DAO in modern Java EE

WROX.COM CODE DOWNLOADS FOR THIS CHAPTER

The wrox.com code download for this chapter is found at www.wrox.com/go/
projavaeedesignpatterns on the Download Code tab. The code is in the Chapter 12 download and individually named according to the names throughout the chapter.

It is unimaginable to think of an enterprise application that does not in some way interact with a data source. The data source may be a relational, object-oriented or NoSQL database, a Lightweight Directory Access Protocol (LDAP) repository, a file system, a web service, or an external system. From whatever source the data comes, the enterprise application must interact with it and perform basic create, retrieve, update, and delete (CRUD) operations. Almost all servers use such data sources to persist sessions or long-running processes seamlessly.

The way in which you use data sources can vary substantially, and their implementation can differ widely. There are different SQL dialects, such as Postgre SQL and Oracle. The simple objective of the data access object (DAO) pattern is to encapsulate access to the data source by providing an interface via which the various layers can communicate with the data source.

This chapter discusses the original problem that the DAO solved and its relevance in modern Java EE applications. Also examined are the role of the related data transfer object (DTO) and how it and the factory pattern fit together with the DAO. In addition, this chapter covers the use of the JPA and ORM in the context of the DAO. You’ll see an implementation of the DAO and how to improve it by using generics. Finally, you will read about the changed role of the pattern and why it is still a valid design pattern.

WHAT IS A DATA ACCESS PATTERN?

The original solution that the DAO pattern proposed was defined in the book Core J2EE Patterns: Best Practices and Design Strategies1 as follows:

Use a data access object (DAO) to abstract and encapsulate all access to the data source. The DAO manages the connection with the data source to obtain and store data.

The problem that was solved with the abstraction and encapsulation of the data source was to guard against the application being dependent on the data source implementation. This decoupled the business layer from the data source. It was thought that if the data source changed, the decoupling would reduce or negate any impact. However, in reality, the data source rarely changed—not even between vendors of the same source type such as between Postgre and MS SQL. It is hard to imagine that a decision would be made to migrate an SQL data source to an XML flat file system, LDAP repository, or web service. This simply didn’t happen. So what value does the DAO pattern have in modern Java EE? Do you really need this pattern?

The DAO pattern is still a valuable pattern, and its original solution is still valid, although the motivation for its implementation has changed in its emphasis. Rather than guarding against the impact of an unlikely change in the data source type, the value is in its mockability and testability and its use in structuring the code and keeping it clean of data access code. There is still value in using it as a way to encapsulate legacy data storage systems and to simplify access to complex implementations of data sources. However, these are more likely to be corner and exceptional cases.

The DAO pattern encapsulates CRUD operations in an interface that is implemented by a concrete class. This interface can be mocked and therefore easily tested, avoiding a connection to the database. Testing is improved because writing tests using mocks is easier than integrating tests with a live database. The DAO’s concrete implement uses low-level APIs such as JPA and Hibernate to perform the CRUD operations.

Data Access Class Diagram

Figure 12.1 shows the class diagram of the DAO, demonstrating the interaction between the client and the DAO and the DTO. Not shown is the optional factory that produces the DAO instance.

images

Figure 12.1 Class diagram of the data access pattern

OVERVIEW OF THE DATA ACCESS PATTERN

The implementation of the DAO pattern involves several components:

  • The DAO interface
  • The concrete implementation of the DAO interface
  • The DAO factory
  • The DTO

The factory, interface, and DTO are optional components, not required components, but you will see these two patterns used with the DAO pattern. The factory pattern is discussed in further detail in Chapter 6, “Factory Pattern.”

Data Transfer Object Pattern

The DTO carries the data retrieved from or persisted to the database across logical layers. For example, to transfer a list of User objects retrieved from the data access layer to the web layer, the service layer would be responsible for transferring from a DAO to a DTO.

The solution that the DTO pattern proposes is defined in Core J2EE Patterns: Best Practices and Design Strategies as follows:

Use a Transfer Object to carry multiple data elements across a tier.

The DTO reduces remote requests across the network in applications that make many method calls to enterprise beans, resulting in improved performance. Sometimes not all the data retrieved from the database is required on the web layer or whatever other layer requires the use of data. So the DTO reduces to just the essential data that the layer requests, thereby optimizing the transfer of data across tiers. This chapter does not go into detail regarding the DTO. It’s recommended that you read the DTO chapter in the Core J2EE Patterns: Best Practices and Design Strategies book.

Java Persistence Architecture API and Object 
Relational Mapping

The Java Persistence API (JPA) manages the application’s interactions with the data source. It specifies how to access, persist, and manage data between the application’s objects and the data source. JPA itself cannot perform CRUD or other data-related operations; it’s just a set of interfaces and implementation requirements. However, a compliant Java EE application server must provide support for its use.

The JPA specification replaces the EJB 2.0 Container-Managed Persistence (CMP) entity beans specification, which was heavyweight and complex. CMP received an adverse reaction from many in the developer community that resulted in the wide adoption of proprietary solutions such as Hibernate and TopLink. This prompted the development of JPA (released with EJB 3.0), which aimed to bring together CMP, Hibernate, and TopLink and seems to have been largely successful.

At the heart of JPA is the concept of an entity. For those of you familiar with CMP, this is what was referred to as an entity bean. An entity is a short-lived object that is capable of being persisted in a database—not as a serialized object but as data. It is a Plain Old Java Object (POJO) whose members are annotated and mapped to a field in the data source. To better understand how this is represented in code, you’ll go through a code snippet.

In the following snippet, you represent a Movie entity class as a POJO that’s appropriately annotated:

@Entity
public class Movie {

    @Id @GeneratedValue
    private Long id;
    private String title;
    private String description;
    private Float price;
    public Movie(){}
    // For brevity, the getters and setters have been left out.

}

As you can see, this is a simple class with just three annotations. The @Entity class level annotations indicate that this class should be treated as an entity class, and the @Id and @Generated annotations mark the id member as an auto-generated identification field. This means that when the entity is persisted, the id field is automatically generated according to the rules of auto-generated fields laid down by the data source. If the data source is a database, then all fields in this entity are persisted to a table called Movie. No other annotations are necessary to indicate which fields are persisted. It is convention over configuration that all fields are persisted unless otherwise annotated. This mapping is referred to as Object Relational Mapping (ORM). It is beyond the scope of this chapter to discuss in detail JPA and ORM, so it is recommended that you read The Java EE 7 Tutorial: Part VIII Persistence.2

IMPLEMENTING THE DATA ACCESS PATTERN IN JAVA EE

Now you’ll go through an example to see how to implement the DAO in Java EE. You are going to use the movie rental domain and a relational database as the data source. You’ll start by creating a movie entity class and annotating it with appropriate JPA annotations, as shown in Listing 12-1.

The class in Listing 12-1 is a simple POJO with appropriate JPA annotations. As briefly mentioned earlier, the @Entity class level annotation indicates that this class should be treated as an entity class and should be managed by the persistence provider. The entity class must have a no-arg constructor that has to be public or protected, although it may have other constructors. It must be a top-level class, which means that it cannot be an enum or an interface, and it must not be final. Also, none of the persistent instance variables or setter/getter methods of the entity class can be final. The entity class must implement the Serializable interface.

You have annotated the id member with @Id and @GeneratedValue, which marks the id member as an auto-generated primary key. All entities must have a primary key, which can be a single member or a combination of members.

The primary key can be one of the following types:

  • Primitive Java types—byte, char, short, int, long
  • Wrapper classes of primitive Java types—Byte, Character, Short, Integer, Long
  • Arrays of primitive or wrapper types—long[], Long[], and so on
  • Java types—String, BigInteger, Date

All members of the entity class are automatically mapped to fields of the same name in the movie table unless they’re annotated with @Transient. This means that the id member maps to the id field in the movie table, the title member maps to the title field in the movie table, and so on.

Next, in Listing 12-2, you create the DAO interface. This should define the basic CRUD methods and any other methods that might prove useful.

Now for the concrete implementation of the DAO interface shown in Listing 12-3. Here you implement the CRUD operations. Notice that the constructor accepts an instance of the EntityManager. This instance is associated with a persistence context that is defined in persistence.xml. The EntityManager API provides create, remove, and persistence functionality as well as the ability to create queries. Any transient field would not be saved or retrieved from the database so expect the data on the transient field to be reset each time the object is re-created.

In Listing 12-4, you create the DAO factory. The EntityManager is created and injected into this class and then passed as a constructor argument to the createMovieDAO method that creates the DAO object. The factory pattern is discussed in more detail in Chapter 6, so please refer to it for more information.

The list of entities in your application is called a persistence unit, and the application’s persistence unit is defined in the persistence.xml configuration file. This file should reside in your application’s META-INF directory. The significant elements of persistence.xml follow:

  • Persistence unit name—You can give the persistence unit a name so that you can define several persistence units and then select them at run time.
  • Persistence unit transaction type—In a Java SE application, the default transaction type is RESOURCE_LOCAL, while in a Java EE environment, the transaction type is JTA. This means that the entity manager participates in the transaction.
  • Provider—This element identifies the class that provides the factory for creating the EntityManager instance.
  • Class—The entity classes used in the application should be listed in the class element.
  • Property—Additional properties can be specified, such as database connection properties and persistence provider properties like options to drop-create new tables.

The EntityManager is associated with a persistence context that is defined in the persistence.xml in Listing 12-5.

The specific data source is defined in this persistence.xml file. In this case, you have defined a Derby database using the eclipse link provider. You have defined the transaction type as JTA because this is a Java EE application implementation, and you have specified the class entity to be com.devchronicles.dataaccessobject.Movie.

Finally, you need to inject the DAO that you have created and use it. The client in Listing 12-6 gets an instance of the DAO injected and uses it to retrieve all movies.

The preceding implementation of the DAO is simplistic and can be improved upon in several ways.

Type-Safe DAO Implementation

One way to improve upon the DAO implementation is to make the DAO interface type-safe. This allows a type-safe DAO that a subinterface can implement for each entity type you want to persist. A base DAO might look like the code in Listing 12-7.

The first type parameter, E, is used to represent the entity, whereas the K type parameter is used as the key. A subinterface that would define methods specific to that entity could then extend the BaseDAO interface.

In Listing 12-8, you create an interface that extends the BaseDAO and defines a method that returns a list of all movies.

A concrete class would implement this interface and provide code for each method.

WHERE AND WHEN TO USE THE DATA ACCESS PATTERN

Some have argued that the DAO is no longer a useful pattern because you can easily invoke the EntityManager directly. This is a reasonable argument because the EntityManager provides a clean API that abstracts away the underlying data access layer. It is also reasonable to suggest that the likelihood of a change in the data provider is remote, which makes the abstraction that the DAO provides less purposeful. Although these arguments have merit, it is still arguable that the DAO has its place in a well-designed Java EE application. (The place might not be where it was originally intended, though.)

The value of extending the BaseDAO as shown in Listing 12-7 for each entity type is in the extensibility of each implementation. Methods that are specific to an entity can be written while maintaining a common interface. You select the DAO implementation once for each entity rather than choosing the right EntityManager method each time it is required to persist or retrieve data.

Named queries can be located within the entity to which they relate. This keeps the queries in a logical place, making maintenance easier. The DAO allows for a uniformed and controlled data access strategy because all access to the entity’s data is required to go via the entity’s DAO. It maintains the principle of single responsibility because only the DAO accesses and manipulates the application’s data.

Don’t forget that even though it’s remote, the data source might change. If it does, you’ll be glad that there is an abstraction on the data layer.

SUMMARY

The DAO has its fans and detractors. The decision of whether to use the pattern in your application should be based on the design requirements of the application. Like all patterns, its use for use’s sake is potentially dangerous and could cause more confusion because over abstract obscures the purpose of the code. Ensure that you understand well the various implementations of the pattern and how it interacts with the DTO and factory pattern.

  EXERCISES  

  1. Write an interface and its implementation for a movie order DAO. You can use the examples in the text as a starting block.

  2. Write a service façade and a DTO that uses the MovieDAO.

NOTES

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset