MVC architecture DTO/Model mapping/conversion
Asked Answered
J

3

10

Using Spring MVC we normally see Controller, Service and Repository layer. The Repository layer uses Entity model which is one to one mapping with database. I thought of following -

  1. Should Service layer use the same Entity model?
  2. Should Service layer use separate Domain model? If yes then the to/fro mapping should be done in Service layer?
  3. Should Controller layer we use the same Domain model?
  4. Should Controller layer use separate DTO model? If yes then the to/fro mapping should be done in Controller layer?
  5. Do we have any simple way to do mapping without writing too much verbose code? I have used Dozer few times in the past.

This question may have been asked but I could not find. So excuse me for duplicate question.

Jeremiah answered 25/1, 2016 at 8:44 Comment(0)
L
7
  1. Yes.
  2. No. The service should work on the Entity model returned by the Repository object.
  3. No. The Controller should use DTO. The DTO should contain the form fields and the Validation annotations (if you are using JSR303).
  4. Yes. DTOs are used in the Controller layer. DTOs should expose a constructor that accepts Entity model. The conversion of Entity model into DTO is done in this constructor. Same case for the Entity model. Entity model should also expose an overloaded constructor that accepts DTO object as argument. Conversion of DTO to Entity model should happen here.
  5. The overloaded constructor of DTO (Entity model as arg) and Entity model (DTO as arg) are verbose.
Landgrabber answered 25/1, 2016 at 9:34 Comment(4)
>Entity model should also expose an overloaded constructor that accepts DTO object as argument What if my Entity has dependent Entities (i.e. one-to-many relationship)? In DTO, I may store their respective IDs, but the DTO -> Entity conversion will require fetching of sub-entities by those IDs. What is the accepted method of handling that?Idio
In that case, create a factory object that will manage the creation and conversion of DTO to Entity model. You can inject your services to this factory object to find objects by their id.Landgrabber
Would this Factory Object not look like a service than? I was thinking about having a flow where all the controllers use DTOs to send and receive data. The controllers communicate with a "DTOService" f.e. Entity1DTOService. This Service would do the mapping from DTO to entity and the other way around. These "DTOServices" communicate with the required "normal services" (f.e. Entity1Service) and they communicate with there respective repository. I don't like using f.e. MapStruct or ModelMapper that is why I'm looking to do it myself, but haven't found any good info or tutorial on it.Vandyke
Why should a service not use a domain model other than the entity? Why should it use the entity? In this case, the principle of single responsibility would not be respected, I think.Mumble
D
4

1) yes,

2) no,

3,4) use entitys for output, but use CommandObjects and DTOs (but not the Entities) for input. This depends on your architecture, but I you not want a client to maniuplate every field of your entities, then you need to separate the objects used for request-mapping (commandobjects) from your domain entities.

Dyaus answered 25/1, 2016 at 8:53 Comment(10)
where should I write conversion code from DTO to Entity and vice versa? Should I convert Entity object in DTO class using another public method say convertToEntity and vice versa OR should I write Separate class for doing this ?Aweigh
In my projects i prefere to have this code in the entity. But my in my projets there is also a rule that states: that every property of an entity is property of at most one DTO..Dyaus
can you please provide a simple example?Aweigh
An example how to invoke an constructor of an DTO? - really?Dyaus
I did not understand your previous statement, coz of my bad English.Aweigh
@Shantaram Tupe: for what part of the code do you need an example?Dyaus
I'm asking about where to do conversion from DTO to Entity and vice versa ? Right now for conversion, In Entity class I've constructor which takes DTO as parameter and vice versa. But somewhere else on SO I read comment, not to use such code.Aweigh
@Shantaram Tupe: every question and answer has a context. So I can not discuss a statement like "somewhere else on SO I read comment". On the other hand I already answered you question where to place the constructor and update method, in this answer I already mentioned the constraint that is needed to have the constructor and update method this way. If you have multi DTOs per field and you add more and more DTOs without changing the entities, then you should place the constuctor and update method in the DTO.Dyaus
@Ralph, Why should a service not use a domain model other than the entity? Why should it use the entity? In this case, the principle of single responsibility would not be respected, I think.Mumble
@Mr.Mars: "A service should not use a domain model other than the entity" - is not what I intended: I think a Service (in a mostly CURD like application) should prefer to use the Domain Entities, if there is for some reason no good Domain Entity for the Service then one need of course to use an other one. But this is the exception and not the preferred way (question 2 asked for the preferred way, so I answered "no")Dyaus
S
1

The entity model used throughout the service layer should be the same. Depending on your architecture and complexity of your application you might want to use different domain models in the service and the controller layer. My recommendation is:

  • Services always work on the Entities which are retrieved and stored using the database
  • Services always take DTOs or simple types as parameters and return only DTOs. Why? Because the DTOs are detached from the database and you neither run into LazyInitializationException nor will you have to use the open-session-in-view anti-pattern.
  • Think of the DTOs as the only model shared between Services and Controllers
  • For the mapping between the Entity and the DTO objects I recommend to use ModelProjector. It is very simple, lean and leaves a minimal footprint

ModelProjector simple maps one model into the other by matching the property names. If they do not match, you can tell it with annotation It is also possible to map complex entity hierarchies onto "flattened" data structures with very straight-forward annotations. The Entity classes remain untouched.

Synchrotron answered 8/8, 2018 at 15:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.