2015-08-13 23:54:40 +02:00
---
layout: pattern
title: Repository
folder: repository
2015-08-15 18:03:05 +02:00
permalink: /patterns/repository/
2019-12-13 21:09:28 +02:00
categories: Architectural
2021-05-19 10:49:05 -06:00
language: en
2015-12-28 15:52:44 +02:00
tags:
2019-12-13 21:09:28 +02:00
- Data access
2015-08-13 23:54:40 +02:00
---
2016-01-03 21:14:30 +01:00
## Intent
2020-09-01 20:18:10 +03:00
Repository layer is added between the domain and data mapping layers to isolate domain objects from
details of the database access code and to minimize scattering and duplication of query code. The
Repository pattern is especially useful in systems where number of domain classes is large or heavy
querying is utilized.
2020-07-20 17:31:58 +03:00
## Explanation
2020-09-01 20:18:10 +03:00
2020-07-20 17:31:58 +03:00
Real world example
2020-09-01 20:18:10 +03:00
> Let's say we need a persistent data store for persons. Adding new persons and searching for them
> according to different criteria must be easy.
2020-07-20 17:31:58 +03:00
In plain words
2020-09-01 20:18:10 +03:00
> Repository architectural pattern creates a uniform layer of data repositories that can be used for
> CRUD operations.
2020-07-20 17:31:58 +03:00
[Microsoft documentation ](https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/infrastructure-persistence-layer-design ) says
2020-09-01 20:18:10 +03:00
> Repositories are classes or components that encapsulate the logic required to access data sources.
> They centralize common data access functionality, providing better maintainability and decoupling
> the infrastructure or technology used to access databases from the domain model layer.
2020-07-20 17:31:58 +03:00
**Programmatic Example**
2020-09-01 20:18:10 +03:00
Let's first look at the person entity that we need to persist.
2020-07-20 17:31:58 +03:00
```java
2021-10-24 16:27:24 +02:00
@ToString
@EqualsAndHashCode
@Setter
@Getter
2020-07-20 17:31:58 +03:00
@Entity
2021-10-24 16:27:24 +02:00
@NoArgsConstructor
2020-07-20 17:31:58 +03:00
public class Person {
@Id
@GeneratedValue
private Long id;
private String name;
private String surname;
private int age;
2021-10-24 16:27:24 +02:00
/**
* Constructor.
*/
2020-07-20 17:31:58 +03:00
public Person(String name, String surname, int age) {
this.name = name;
this.surname = surname;
this.age = age;
}
}
```
2020-09-01 20:18:10 +03:00
We are using Spring Data to create the `PersonRepository` so it becomes really simple.
2020-07-20 17:31:58 +03:00
```java
@Repository
public interface PersonRepository
extends CrudRepository< Person , Long > , JpaSpecificationExecutor< Person > {
Person findByName(String name);
}
```
2020-09-01 20:18:10 +03:00
Additionally we define a helper class `PersonSpecifications` for specification queries.
2020-07-20 17:31:58 +03:00
```java
public class PersonSpecifications {
public static class AgeBetweenSpec implements Specification< Person > {
2020-07-30 20:28:47 +03:00
private final int from;
2020-07-20 17:31:58 +03:00
2020-07-30 20:28:47 +03:00
private final int to;
2020-07-20 17:31:58 +03:00
public AgeBetweenSpec(int from, int to) {
this.from = from;
this.to = to;
}
@Override
public Predicate toPredicate(Root< Person > root, CriteriaQuery< ?> query, CriteriaBuilder cb) {
return cb.between(root.get("age"), from, to);
}
}
public static class NameEqualSpec implements Specification< Person > {
public String name;
public NameEqualSpec(String name) {
this.name = name;
}
public Predicate toPredicate(Root< Person > root, CriteriaQuery< ?> query, CriteriaBuilder cb) {
return cb.equal(root.get("name"), this.name);
}
}
}
```
2020-09-01 20:18:10 +03:00
And here's the repository example in action.
2020-07-20 17:31:58 +03:00
```java
var peter = new Person("Peter", "Sagan", 17);
var nasta = new Person("Nasta", "Kuzminova", 25);
var john = new Person("John", "lawrence", 35);
var terry = new Person("Terry", "Law", 36);
repository.save(peter);
repository.save(nasta);
repository.save(john);
repository.save(terry);
LOGGER.info("Count Person records: {}", repository.count());
var persons = (List< Person > ) repository.findAll();
persons.stream().map(Person::toString).forEach(LOGGER::info);
nasta.setName("Barbora");
nasta.setSurname("Spotakova");
repository.save(nasta);
repository.findById(2L).ifPresent(p -> LOGGER.info("Find by id 2: {}", p));
repository.deleteById(2L);
LOGGER.info("Count Person records: {}", repository.count());
repository
.findOne(new PersonSpecifications.NameEqualSpec("John"))
.ifPresent(p -> LOGGER.info("Find by John is {}", p));
persons = repository.findAll(new PersonSpecifications.AgeBetweenSpec(20, 40));
LOGGER.info("Find Person with age between 20,40: ");
persons.stream().map(Person::toString).forEach(LOGGER::info);
repository.deleteAll();
2020-09-01 20:18:10 +03:00
```
Program output:
```
Count Person records: 4
Person [id=1, name=Peter, surname=Sagan, age=17]
Person [id=2, name=Nasta, surname=Kuzminova, age=25]
Person [id=3, name=John, surname=lawrence, age=35]
Person [id=4, name=Terry, surname=Law, age=36]
Find by id 2: Person [id=2, name=Barbora, surname=Spotakova, age=25]
Count Person records: 3
Find by John is Person [id=3, name=John, surname=lawrence, age=35]
Find Person with age between 20,40:
Person [id=3, name=John, surname=lawrence, age=35]
Person [id=4, name=Terry, surname=Law, age=36]
2020-07-20 17:31:58 +03:00
```
2015-08-13 23:54:40 +02:00
2019-12-07 20:01:13 +02:00
## Class diagram
2020-09-01 20:18:10 +03:00
2015-08-13 23:54:40 +02:00

2016-01-03 21:14:30 +01:00
## Applicability
2020-09-01 20:18:10 +03:00
2016-01-03 21:14:30 +01:00
Use the Repository pattern when
2015-08-13 23:54:40 +02:00
2020-09-01 20:18:10 +03:00
* The number of domain objects is large.
* You want to avoid duplication of query code.
* You want to keep the database querying code in single place.
* You have multiple data sources.
2015-08-13 23:54:40 +02:00
2016-01-03 21:14:30 +01:00
## Real world examples
2015-08-13 23:54:40 +02:00
2015-08-15 18:03:05 +02:00
* [Spring Data ](http://projects.spring.io/spring-data/ )
2015-11-27 11:22:33 +08:00
2016-01-03 21:14:30 +01:00
## Credits
2015-11-27 11:22:33 +08:00
* [Don’ t use DAO, use Repository ](http://thinkinginobjects.com/2012/08/26/dont-use-dao-use-repository/ )
* [Advanced Spring Data JPA - Specifications and Querydsl ](https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/ )
2019-12-07 20:01:13 +02:00
* [Repository Pattern Benefits and Spring Implementation ](https://stackoverflow.com/questions/40068965/repository-pattern-benefits-and-spring-implementation )
2020-07-07 21:19:14 +03:00
* [Patterns of Enterprise Application Architecture ](https://www.amazon.com/gp/product/0321127420/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321127420&linkCode=as2&tag=javadesignpat-20&linkId=d9f7d37b032ca6e96253562d075fcc4a )
2020-07-20 17:31:58 +03:00
* [Design patterns that I often avoid: Repository pattern ](https://www.infoworld.com/article/3117713/design-patterns-that-i-often-avoid-repository-pattern.html )