The Data Access Object pattern
21st Sep 2020 by Aneesh Mistry

Key Takeaways
• Understand when to use the DAO pattern and the benefits it brings to software design.
• Explore the use of Spring data JPA as a repository layer.
• Implement the DAO pattern to support multiple repository layer implementations.

The Data Access Object (DAO) pattern

The DAO pattern is used within software development to separate the service layer from the repository layer of an application. The service layer of an application will apply business logic to a user request that is received from a controller and will send the request to the repository layer where it is persisted into a data store. To learn more about the multiple layers of an application, visit a previous blog here.

The DAO pattern uses dependency inversion to loosely couple the service layer from the repository layer. The DAO abstraction enables the service layer to remain agnostic to the implementation of the data store, whether that be a relational database, lightweight directory access protocol, business to business data store or any other type of persistance. The DAO supports the use of the open-closed principle where the service layer can remain unchanged while the underlying data store is dynamic.

A top-down view of the DAO pattern

The DAO pattern is divided between the service layer which intercepts a request from the controller, and the repository layer which is used within the service layer to persist the change to the data store.

Layers of the application

The DAO pattern introduces an abstracted relationship between the service layer and the data stores such that the service layer becomes agnostic to the implementations of the data store by the DAO:

Layers of the application with DAO pattern


Using the DAO design pattern

The DAO pattern in this blog is being used to demonstrate an Estate agent application that will use the repository layer to store properties that are for sale. The application will include a controller API to save, update or delete properties that are stored within the data store. The DAO implementation is used to encapsulate the data store for the service to use, and to access.


DAO Participants

The DAO defines 6 key participants involved with the creation and execution of a request with the persisted data store:
• Business user: The request from the user to obtain or modify data.
• Service: the business logic service to process the request.
• Entity object: instances of the data as an Object representation.
• DAOInterface: interface with repository methods to interact with the data store.
• DAOImpl: individual implementations of DAOInterface to interact with different data storage options.
• Data store: the storage of the data in its persisted form.

Layers of the application


Implementing the DAO

The DAO is implemented as an interface for the CRUD operations to be performed upon the data store. The implementations of the interface enable the growth of the application to support further data stores as the DAO interface is passed as a service to the service layer to use.

The DAO interface exists below with descriptive operations to be performed upon the database:

public interface PropertyDao {

	public List<Property> getProperties();

	public void saveProperty(Property property);

	public Property getProperty(int id);

	public void deleteProperty(int id);
	
}

The DAO Implementation uses the Hibernate SessionFactory to create transactions to the data store:

@Repository
public class PropertyDaoImpl implements PropertyDao {

	@Autowired
	SessionFactory sessionFactory;
	
	@Override
	public List<Property> getProperties() {
		Session session = sessionFactory.getCurrentSession();
		Query<Property> query = session.createQuery("from property order by id", Property.class);
		
		List<Property> result = query.getResultList();
		return result;
	}

	@Override
	public void saveProperty(Property property) {
		Session session = sessionFactory.getCurrentSession();
		session.saveOrUpdate(property);
	}

	@Override
	public Property getProperty(int id) {
		Session session = sessionFactory.getCurrentSession();

		Property property = session.get(Property.class, id);
		return property;
	}

	@Override
	public void deleteProperty(int id) {
		Session session = sessionFactory.getCurrentSession();

		Query<Property> query = session.createQuery("delete from Property where id=:id", Property.class);
		query.executeUpdate();
	}

}


Implementing the service layer

The service layer is used to obtain requests from the controller to be passed down to the repository layer.

@Service
public class PropertyService {

	@Autowired
	private PropertyDao repositoryService;
	
    @Transactional
	public void save(Property property) {
		repositoryService.saveProperty(property);		
	}

    @Transactional
	public List<Property> getAllProperties() {
		return repositoryService.getProperties();
	}
	
    @Transactional
	public Property getProperty(int id) {

		Property property = repositoryService.getProperty(id);
		
		return property;
	}	
}

While it may appear to be an additional and unnecessary layer to access the PropertyDaoImpl, the service layer would typically provide additional functionality to the transaction such as logging, authorisation and security. The PropertyDaoImpl is passed in as a service to the layer to provide access to the data store. Each method is marked as @Transactional to assign transactional semantics to the method call. The semantics define the scope for a single database transaction using the Session instance created to synchronize changes that are persisted to the data store.


Using Spring data JPA as a repository layer

In the current application, the service layer creates transactional requests to the repository layer where a session with the data store is used. The DAO pattern is used to define the CRUD methods which are required to the data store.

The use of the Hibernate Session objects in the repository layer requires verbose configuration to create the bean for the Session. The Spring Data JPA abstraction offers an out-of-the-box interface to support the CRUD operations made to a data store thus simplifying the implementation of the repository layer.

The Spring Data JPA package can be obtained within the dependencies:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

The Spring data JPA repository layer is implemented as an extension of the interface which can then be passed into the service layer as a service:

public interface JpaRepositoryImpl extends JpaRepository<Property, Integer>{
	
}

The JpaRepositoryImpl extends the JpaRepository interface and introduces two generic values for the interface. The Property generic is used to identify the entity each record of the data store will coincide with. The Integer identifies the type the primary key is for the table.

The interface is autowired into the service layer and provides the following methods amongst many others to support interaction with the data store:
findAll() to return a list of all records as Property instances from the data store.
findById(int id) to return a single record as a Property instance, identified by the primary key.
save(Property) to update or save a record to the data store.

By implementing Spring data JPA into the application, the DAO is pre-defined to cover all the actions required to the data store. As a result, the extension of behaviour from the interface can be defined where the methods are hidden by the JPA abstraction. We can create a new extension of the interface with a different Entity Object as the Generic to define a new data store for the repository layer.
The Spring data package encapsulates all method calls to the interface with @Transaction behind the scenes. As a result, the service layer will no longer require the @Transactional annotation upon each method.

The updated Service layer will use the Spring data JPA interface:

@Service
public class PropertyService {

	@Autowired
	private JpaRepositoryImpl repositoryService;
	
	
	public void save(Property property) {
		
		repositoryService.save(property);	
	}
	
	public List<Property> getAllProperties() {

		return repositoryService.findAll();
	}
	
	public Property getProperty(int id) {

		Property property = repositoryService.findById(id).get();
		return property;
	}
}


Realising the benefits of DAO

The DAO pattern generalises the transactions that a Service layer can make to the repository layer thus opening the Repository layer to implementations of the transactions. We can use Spring Hibernate to provide a granular approach to defining data stores, sessions and transactions to handle the different implementations of the Repository layer.

As the extension of the repository layer is enabled by the DAO, we can use alternative strategies for the repository layer including the Spring data JPA repository implementation. Provided the DAO supports all the defined methods, the DAO can represent various Repository implementations across data storage medium, transaction definitions and sessions to benefit the application implementation and developer experience.


Conclusion

The data access object pattern is used to separate the service layer from the repository layer. As a result, multiple implementations of the repository layer can be used to represent different data stores and abstractions of the repository layer.
The Hibernate and Spring data packages support multiple designs of the repository layer to provide varying abstractions of the transactions made to the data store. Furthermore, the DAO pattern enables the support of multiple data stores and repository layers.

This blog has used the DAO pattern to support the growth of an application with multiple data stores. Two different strategies have been used to demonstrate how the DAO can be applied to different levels of abstractions of the repository layer. The specific support for database sessions and transactions can therefore be delegated to the implementations of the DAO to enable the repository layer to remain open to extension. You can find the source code from this blog on GitHub here.


Share this post