Repository Pattern is a part of Domain-Driven Design, It abstract out the way to access data from the database. It mediates between the domain and data mapping layers using a Repository interface for accessing domain objects. In this article, we will understand what is a Repository pattern, Query Object, Mapping Metadata and how it can be implemented.
Repository interface exposes methods for adding, updating, deleting and finding records from the database. Repository implementation encapsulates the database connection and way to execute a query on the database.
The Repository takes the help of Query Object to construct the database query and map the result of the query after execution to an entity (or domain object) using Mapping Metadata.
Query Object is an in-memory (programming object) representation of database query. The query object is implemented as an interpreter pattern and abstracts logic to create a database query string. Query objects de-couples the database schema and domain object as we refer to in-memory objects (classes and fields). This gives us the flexibility to form database queries from program objects (Query Object).
Once the database query is executed by Repository, Query Object needs to know how to map a resultset row to domain object (or entity). This can be done by providing Mapping Metadata to the Query Object.
Mapping Metadata holds object-relational mapping details as metadata. Mapping Metadata can be provided by mean of Mapper object (like in a Spring framework we use RowMapper or ResultSetMapper), it can be held in a metadata file (example an XML or JSON file like a Mybatis ResultMap XML tag in mapper file) or can be annotated on the class field.
Let’s look into the implementation details of the Repository Pattern. We are going to implement a repository pattern simply.
- Expose Repository interface with CRUD methods
- Implement a Query Object
- Implement a Mapper Metadata
Repository interface exposes CRUD methods: Create, Retrieve(Find), Update, Delete.
Two types of query objects: Here we are using a simple implementation of query object which will encapsulate string SQL query and query parameters.
Query: SqlQuery wraps the SQL database query string and parameters.
- FinderQuery: SqlFinderQuery is an extension of SqlQuery and encapsulates the way to map database resultset to domain objects using RowMapper object.
A SqlRowMapper is an interface to map resultset to domain objects or entities.
SQL Repository Implementation
A SqlRepositoryImpl is an implementation of a Repository interface that encapsulates JDBC DataSource and implements CRUD (Create, Retrieve, Update & Delete)methods.
Heres a class diagram of above code:
When to use Repository Pattern
If you are dealing with multiple entities or domain objects, and have to write many database queries then a Repository Pattern will be helpful to reduce the redundant code, reduce the amount of code needed to implement for all queries.
Repository pattern is also beneficial when connecting to multiple data sources. Repository abstract out the implementation of how to access the database, database client (can be a JDBC client in case of a relational database) and takes care of all data access operations. With this abstraction, you can easily switch the target database for domain objects.
Please visit GitHub repository Persistence, which is a persistence framework implemented using a repository pattern.