Spring Entities should convert to Dto in service?
We are talking about software architecture and as always when we are talking about software architecture there are a thousand ways of doing something and many opinions about what is the best way. But there is no best way, everything has advantages and disadvantages. Keep this in mind!
Typically you have different layers:
- A persistence layer to store data
- Business layer to operate on data
- A presentation layer to expose data
Typically, each layer would use its own kind of objects:
- Persistence Layer: Repositories, Entities
- Business Layer: Services, Domain Objects
- Presentation Layer: Controllers, DTOs
This means each layer would only work with its own objects and never ever pass them to another layer.
Why? Because you want each layer to be separated from the other layers. If you would use entities in your controller, your presentation would depend on how your data is stored. That's really bad. Your view has nothing to do with how the data is stored. It shouldn't even know that or how data is stored.
Think of that: You change your database model, e.g. you add a new column to one of your database tables. If you pass the entities to your controller (or worse: your controller exposes them as JSON), a change at the database would result in a change in your presentation. If the entities are directly exposed as JSON, this might even result in changes in JavaScript or some other clients which are using the JSON. So a simple change in the database might require a change in the JavaScript front end, because you couple your layers very tight. You definitely don't want that in a real project.
How? You doubt that this is practical, so just a small example of how to do that in (pseudo) code:
class Repository {
public Person loadById(Long id) {
PersonEntity entity = loadEntityById(id);
Person person = new Person();
person.setId(entity.getId());
person.setName(entity.getFirstName + " " + entity.getLastName());
return person;
}
}
In this example, your repository would use entities internally. No other layer knows or uses this entities! They are an implementation detail of this particular layer. So if the repository is asked to return a "person", it works on the entity, but it will return a domain object. So the domain layer which works with the repo is save in the case the entities need to be changed. And as you can see in the case of the name, the domain and the database might be different. While the database stores the name in first name and last name, the domain only know a single name. It's a detail of the persistence how it stores the name.
The same goes for controllers and DTOs, just another layer.
Conversion of DTO to entity and vice-versa
I think you are asking about where to write whole entity-->DTO conversion logic.
Like Your entity
class StudentEntity {
int age ;
String name;
//getter
//setter
public StudentDTO _toConvertStudentDTO(){
StudentDTO dto = new StudentDTO();
//set dto values here from StudentEntity
return dto;
}
}
Your DTO Should be like
class StudentDTO {
int age ;
String name;
//getter
//setter
public StudentEntity _toConvertStudentEntity(){
StudentEntity entity = new StudentEntity();
//set entity values here from StudentDTO
return entity ;
}
}
And Your Controller should be like
@Controller
class MyController {
public String my(){
//Call the conversion method here like
StudentEntity entity = myDao.getStudent(1);
StudentDTO dto = entity._toConvertStudentDTO();
//As vice versa
}
}
Domain object to persisting entity converting
First of all, that's quite a great idea to separate your persistent entity from your domain objects. I used to deal with setups where both approaches have been mixed together and that lead us to a complete mess afterwards.
The approach you're looking for is called 'Bean mapping'. There are a lot of such mappers around, Dozer seems to be the most widely used, but it's reflection-based and thus it's quite slow. Orika has good balance between performance and extensibility, but it also leads to some weird classloading issues in Java EE environment.
Most of bean mappers perform automatic mapping for equally named fields, extra conversions may be defined for 'simple transformations' you have mentioned above. Here's the example of Orika configuration for particular Web-to-DB entity mapping (with workaround for the classloading issue mentioned above applied): https://bitbucket.org/__jtalk/jacra/src/default/JAcraEJB/src/main/java/me/jtalk/jacra/utils/mapper/MappersRegistration.java
You can then use those mappers like:
@Inject
@UserMapper
private BoundMapperFacade<UserEntity, UserWeb> userMapper;
...
UserEntity entity = userMapper.mapReverse(userWeb);
mapper.map(entity);
Replace this persistent entity with a simple POJO or DTO object?
DO NOT put your Entity model into Controller method. You must create another model like MissionRequestModel
for @RequestBody
, and then convert your request model to your entity
public class MissionRequestModel {
private String name;
private String description;
}
@PostMapping("/ajouterMission")
@ResponseBody
public int ajouterMission(@RequestBody MissionRequestModel missionRequestModel) {
Mission mission = new Mission(missionRequestModel);
}
Persistence entities as data transfer objects
I would say that it is OK to do so (in fact the major advantage for these ORMs were to use these domain objects in different layers w/o having unnecessary DTOs) if you follow the following guidelines:
- You don't extend the session boundaries i.e., any changes related to database should always be done using the Data Access Layer you have defined and not through these passed objects in other layers.
- Any data that you need in other layer (layers above the Data Access Layer like Business Logic Layer and Presentation Layer) is pre-populated in these objects otherwise you will get exceptions according to the ORM behavior.
- Don't extend the session boundaries for resolving the issue mentioned in No. 2
DTOs vs Serializing Persisted Entities
DTOs. Use AutoMapper for object-to-object mapping
Related Topics
MVC 4 How Pass Data Correctly from Controller to View
Create Out-Of-Process Com in C#/.Net
How to Get Current User Who's Accessing an ASP.NET Application
An Expression Tree Lambda May Not Contain a Null Propagating Operator
C# How to Loop User Input Until the Datatype of the Input Is Correct
How to Programmatically Change Printer Settings with the Webbrowser Control
How Does C# Choose with Ambiguity and Params
Convert String to Decimal, Keeping Fractions
Sorting an Array Related to Another Array
How to Display the String HTML Contents into Webbrowser Control
Excel Interop: _Worksheet or Worksheet
ASP.NET Core 2.0 Disable Automatic Challenge
Task.Factory.Startnew with Async Lambda and Task.Waitall