Search code examples
design-patternsdto

How we should handle the DTO?


I have 2 table, Patient and Registration and the relationship is one-to-many.

In the Registration module when I want to edit the registration, I call GetRegistrationByID(int id) to get the data by its ID and also select the PatientCode and PatientName and parse it to DTO.

In another module, I reuse the GetRegistrationByID(int id) but I need more information on the Patient's information such as gender, place and date of birth, address, village, district, province, and phone no.

I have 2 options for this case, change the RegistrationDTO to include more Patient's information but the consequence is in registration module when I call the GetRegistrationByID(int id) the RegistrationDTO is become bigger. Because I only need PatientCode and PatientName, and now there are extra information which is not necessary.

The second option is I create another method GetPatientInfoByRegistrationID(int id) but the consequence is there are 2 times round-trip to database. I think it violetes the DTO principle

A data transfer object (DTO1[2]) is an object that carries data between processes. The motivation for its use is that communication between processes is usually done resorting to remote interfaces (e.g. web services), where each call is an expensive operation.[2] Because the majority of the cost of each call is related to the round-trip time between the client and the server, one way of reducing the number of calls is to use an object (the DTO) that aggregates the data that would have been transferred by the several calls, but that is served by one call only.[2]

I'm trying to learn how to make the code better, so which one should I choose? Please add the explanation why it's better


Solution

  • The expense may not be as big as you think. Carefully check this section:

    Because the majority of the cost of each call is related to the round-trip time between the client and the server, one way of reducing the number of calls is to use an object (the DTO) that aggregates the data that would have been transferred by the several calls, but that is served by one call only.

    What this tells you is that the DTO is used for communication between the server and some client, which may include network overhead (I say may because in some cases it could be one the same server, such as DTOs used to fill in server-side data while generating HTML to return to a browser client). This is why you want to include the information that will be needed into a single DTO rather than having separate calls for everything. For example, if some client is going to need registration and patient info, you want to avoid having them needing to make two separate calls, which is why you return data bundled in a DTO. Otherwise you would have two full round-trips. However, that doesn't mean you need to avoid multiple database queries at all costs. The DTO is being composed on the server side, and two database queries on the server to create the DTO is not as dramatic as requiring two full client/server round-trips.

    Another consideration is that often multiple database queries may not even be necessary. Object-relational mapping frameworks such as the Java Persistence API usually let you map relations between entities and specify whether they should be fetched lazily (only when requested) or eagerly. Eager fetches can be optimized by the ORM by using joins to require only a single query. Just because there's information from more than one entity in a DTO, does not mean that it will necessarily require multiple database queries.

    Then for the design of your DTOs. All the information does not need to be in one single class. The DTOs can mirror the persisted entities and their relations. In your case you have a Patient and Registration table, so you can have corresponding DTO classes like PatientDTO and RegistrationDTO, where the patient DTO can have a list of registrations, and the registration DTO a field for the related patient. Composition like this makes it easier to get isolated data (for example if you want only patient data, but not the registrations) and re-use classes.

    For different data sets you do not necessarily need different DTOs. Just because one call should only include the patient name and code, while another call includes more information, doesn't mean you need separate DTO classes for this. Just define a class that can hold all information (for its corresponding entity) and only fill in what is needed. After all, the client usually knows what it wants from the call. If you want to be able to differentiate between data that is missing because it's not in the database, and that which simply wasn't mapped, you could use some marker per field to indicate if it was supposed to be set or not. Or the field types could be some wrapper object that gets flagged when its set, so you'll now if it was null or some other default value intentionally or not.

    Finally, DTOs don't necessarily need to follow the structure or property names of entities. They're intended for the client in the first place, so design for that. DTOs can be abstractions to hide the persistent structure that a client doesn't need to know about. But in practice it's usually less confusing to keep the entities and DTOs similar, if not identical. Well-designed entities will have a clear structure and understandable properties anyway.