Browser docs

Data Mapper

Intent

Data Mapper is the software layer that separates the in-memory objects from the database. Its responsibility is to transfer data between the objects and database and isolate them from each other. If we obtain a Data Mapper, it is not necessary for the in-memory object to know if the database exists or not. The user could directly manipulate the objects via Java command without having knowledge of SQL or database.

Explanation

Real world example

When a user accesses a specific web page through a browser, he only needs to do several operations to the browser. The browser and the server will take the responsibility of saving data separately. You don’t need to know the existence of the server or how to operate the server.

In plain words

A layer of mappers that moves data between objects and a database while keeping them independent of each other.

Wikipedia says

A Data Mapper is a Data Access Layer that performs bidirectional transfer of data between a persistent data store (often a relational database) and an in-memory data representation (the domain layer). The goal of the pattern is to keep the in-memory representation and the persistent data store independent of each other and the data mapper itself. This is useful when one needs to model and enforce strict business processes on the data in the domain layer that do not map neatly to the persistent data store.

Programmatic Example

We have the student class to defining Students’ attributes includes studentId, name and grade. We have an interface of StudentDataMapper to lists out the possible behaviour for all possible student mappers. And StudentDataMapperImpl class for the implementation of actions on Students Data.

 1
 2public final class Student implements Serializable {
 3
 4    private static final long serialVersionUID = 1L;
 5
 6    @EqualsAndHashCode.Include
 7    private int studentId;
 8    private String name;
 9    private char grade;
10
11
12    public interface StudentDataMapper {
13
14        Optional<Student> find(int studentId);
15
16        void insert(Student student) throws DataMapperException;
17
18        void update(Student student) throws DataMapperException;
19
20        void delete(Student student) throws DataMapperException;
21    }
22
23    public final class StudentDataMapperImpl implements StudentDataMapper {
24        @Override
25        public Optional<Student> find(int studentId) {
26            return this.getStudents().stream().filter(x -> x.getStudentId() == studentId).findFirst();
27        }
28
29        @Override
30        public void update(Student studentToBeUpdated) throws DataMapperException {
31            String name = studentToBeUpdated.getName();
32            Integer index = Optional.of(studentToBeUpdated)
33                    .map(Student::getStudentId)
34                    .flatMap(this::find)
35                    .map(students::indexOf)
36                    .orElseThrow(() -> new DataMapperException("Student [" + name + "] is not found"));
37            students.set(index, studentToBeUpdated);
38        }
39
40        @Override
41        public void insert(Student studentToBeInserted) throws DataMapperException {
42            Optional<Student> student = find(studentToBeInserted.getStudentId());
43            if (student.isPresent()) {
44                String name = studentToBeInserted.getName();
45                throw new DataMapperException("Student already [" + name + "] exists");
46            }
47
48            students.add(studentToBeInserted);
49        }
50
51        @Override
52        public void delete(Student studentToBeDeleted) throws DataMapperException {
53            if (!students.remove(studentToBeDeleted)) {
54                String name = studentToBeDeleted.getName();
55                throw new DataMapperException("Student [" + name + "] is not found");
56            }
57        }
58
59        public List<Student> getStudents() {
60            return this.students;
61        }
62    }
63}

The below example demonstrates basic CRUD operations: Create, Read, Update, and Delete between the in-memory objects and the database.

 1@Slf4j
 2public final class App {
 3
 4  private static final String STUDENT_STRING = "App.main(), student : ";
 5
 6  public static void main(final String... args) {
 7
 8    final var mapper = new StudentDataMapperImpl();
 9
10    var student = new Student(1, "Adam", 'A');
11
12    mapper.insert(student);
13
14    LOGGER.debug(STUDENT_STRING + student + ", is inserted");
15
16    final var studentToBeFound = mapper.find(student.getStudentId());
17
18    LOGGER.debug(STUDENT_STRING + studentToBeFound + ", is searched");
19
20    student = new Student(student.getStudentId(), "AdamUpdated", 'A');
21
22    mapper.update(student);
23
24    LOGGER.debug(STUDENT_STRING + student + ", is updated");
25    LOGGER.debug(STUDENT_STRING + student + ", is going to be deleted");
26
27    mapper.delete(student);
28  }
29
30  private App() {
31  }
32}

Program output:

15:05:00.264 [main] DEBUG com.iluwatar.datamapper.App - App.main(), student : Student(studentId=1, name=Adam, grade=A), is inserted 15:05:00.267 [main] DEBUG com.iluwatar.datamapper.App - App.main(), student : Optional[Student(studentId=1, name=Adam, grade=A)], is searched 15:05:00.268 [main] DEBUG com.iluwatar.datamapper.App - App.main(), student : Student(studentId=1, name=AdamUpdated, grade=A), is updated 15:05:00.268 [main] DEBUG com.iluwatar.datamapper.App - App.main(), student : Student(studentId=1, name=AdamUpdated, grade=A), is going to be deleted

This layer consists of one or more mappers (or data access objects) that perform data transfer. The scope of mapper implementations varies. A generic mapper will handle many different domain entity types, a dedicated mapper will handle one or a few.

Explanation

Real-world example

When accessing web resources through a browser, there is generally no need to interact with the server directly; the browser and the proxy server will complete the data acquisition operation, and the three will remain independent.

In plain words

The data mapper will help complete the bi-directional transfer of persistence layer and in-memory data.

Wikipedia says

A Data Mapper is a Data Access Layer that performs bidirectional transfer of data between a persistent data store (often a relational database) and an in-memory data representation (the domain layer).

Programmatic example

Class diagram

alt text

Applicability

Use the Data Mapper in any of the following situations

  • when you want to decouple data objects from DB access layer
  • when you want to write multiple data retrieval/persistence implementations

Tutorials

Known uses

Consequences

Neatly mapped persistence layer data Data model follows the single function principle

Credits