This blog article is part of a “series of blog articles” about common pitfalls using JPA and ways to avoid them. In this article, we describe a problem with unextected changes when using DTOs.
A lot of applications use data transfer object (DTO) to transfer data between GUI and server. So how to store the changes from the DTO into the corresponding entity instance? We have seen one attempt causing a lot of trouble.
The code creates a new entity instance, transfers the attribute values including that change from the DTO into the entity and then calls merge on the entity:
EmpDTO empDto = ... // DTO instance with changes from GUI Employee emp = new Employee(); emp.setId(empDTO.getId()); emp.setFirstname(empDTO.getFirstname()); ... emp = em.merge(emp);
The problem occurs if the DTO only includes a subset of the persistence attributes of the entity, especially if it does not include all of the relationships. If so, the entity updated with the DTO values has attributes or relationships with null values. This state is stored in the database at the end of the transaction, meaning the attributes or relationships are removed.
The correct code retrieves the entity from the database and stores the changes from the DTO:
EmpDTO empDto = ... // DTO instance with changes from GUI Employee emp = em.find(Employee.class, empDTO.getId()); emp.setFirstname(empDTO.getFirstname()); ...
Recommendation: store the field values into an entity retrieved from the database.
You can find an example of this pitfall and its solution in the class CopyDTOToEntityExperiment in this project: https://github.com/akquinet/jpapitfalls.git.