Let's consider a Spring Boot (Spring Data JPA) application with a controller and a service as in the below example:
processEntity()
fetches an object from the database and processes/updates it.publishEntity()
is a separate method, again fetching the object from the database, and publishing it to another system. It requires the "latest" state of the entity from the database.
I found several blog posts and articles which recommend not to operate with the entity in the controller, i.e., outside the scope of a transaction. So my classes look like this:
@Service
public SomeService {
@Transactional
public void processEntity(long id) {
final SomeEntity someEntity = entityRepository.findById(id);
// process entity...
entityRepository.save(someEntity);
}
@Transactional(readOnly = true)
public void publishEntity(long id) {
final SomeEntity someEntity = entityRepository.findById(id);
// publish entity to another system...
}
}
@RestController
public SomeController {
@GetMapping(path = "/api/entity")
public ResponseEntity<Void> getEntity() {
someService.processEntity(1);
someService.publishEntity(1);
}
}
Is this approach reasonable? Or are there better patterns for such a use case? Would it be considered "bad practice" if processEntity
returned the entity itself to the controller which passes it to publishEntity
?
CodePudding user response:
Returning entities and receiving entities in your Controllers is usually a bad practice and a common source of issues (don't get me wrong, it actually works, but unless your use cases are so simple you will most probably face some constraints while doing so). You should use DTOs instead, which would be a similar class to your entity but that can represent multiple views from your domain model (your entities in your case).
There are multiple reasons for using DTOs:
- It allows a separation of concerns between your domain model and your "public" model, allowing you to change one without needing to change the other.
- It allows you to easily have multiple views of your entities without the need to include Jackson magic annotations to include or exclude some properties in your entity classes.
You can read more about this in the following online resource: https://www.baeldung.com/java-dto-pattern.
If you decide to use DTOs, consider also using a mapper such as the following ones:
I don't really like using them (I prefer to do the mapping on my own), but you may find them useful. The mapping may be done in the Service layer itself or in the Controller layer. There are pros and cons for each one of the approaches, but I would say it really comes to your preference.
CodePudding user response:
It is recommended to use DTO objects between controller and service. In case you decide the remove the database and use some external system, later on, then the controller layer will not be impacted.