I've seen a few articles stating that a repository should only return full domain models for method calls such as GetAll(). But what if all I need is a list where each item is only made up of 2 properties from a domain model that has 30 properties? I would like to display a list departments where the list only shows a department name, and location. From that list a user can select one department and request its details. From there I can make another repository call to return the full domain model for what was selected and allow the typical crud operations to take place.
However, if I'm not supposed to use a repository to return a subset of the full domain model then what is the suggested approach? I suppose I could just return a list of full domain models but that seems a waste of network bandwidth to bring so much data over the wire I won't use. If I create another model to represent the 2 properties of interest that seems like another bulk load of work to do since each model I have has its own repository and service module for repository access.
What are the suggested methods to retrieve a subset of a full domain model from a repository? Also, I don't see what would happen if I violate the rule of pulling only full models by also pulling partial model data as well which would only be used for pick lists.
Your repositories should return domain objects and the client of the repository can decide if it needs to do the mapping. By mapping the domain objects to view models (or something else) inside a repository, you prevent the client of your repositories from getting access to the underlying domain object.
A typical example is a DTO projection, which is the most efficient one for read-only operations. To use it in a derived or custom JPQL query, you only need to change the return type of your repository method to your DTO class or interface.
First, it's important to remember that you don't have to use DTOs. They are a programming pattern, and your code will work just fine without them. If you want to keep the same data representation in both layers, you can just use your entities as DTOs.
DTOs are mostly used out of the hexagon, in the delivery mechanism. On the other hand domain models should promote a good object oriented design with proper encapsulation. They belong in the hexagon. However it's not always clear where to use a DTO and a domain model, where and how to convert one into the other.
In my opinion, this can be considered a highly subjective question.... My suggestion is based on DDD
practices.
In the context of DDD
, the repository should always return a domain object (i.e., an Aggregate
). Aggregates are the basic element of transfer of data storage - you request to load or save whole aggregates. It's up to the application layer transform the data into a model / DTO
that makes sense for the view.
To address your concerns:
The pick list example that your describe is a great candidate for a DTO. If you create a DTO to represent two properties to support a view, you are creating a POCO object. This object is lightweight and cheap to create. You can use tools such as AutoMapper to assist with the mapping between the DTO and Domain Model. When it's time to change the view, your changes are usually isolated to the DTO object and its mapping. You have not leaked the concept of a view through your application layer into the domain layer.
The DTO will cut down on the bandwidth cost for the requesting client (i.e., you are not returning a domain entity with 30 properties and showing your entity in public)
You can use a single repository to support your Department picklist view and CRUD operations for the Department entity.
Use one domain model. However create as many DTOs that your need to support views from that domain model or models.
At the end of the day, DDD is not cheap and it's not a silver bullet.
If you have a simple problem to solve, then use simple CRUD with a model that makes sense for you. These are just guidelines...
DDD makes sense for developing software of extremely high essential complexity (with a lot of correlated business rules). And/or software with clear future, where the Domain Model can outlast the infrastructure, or where the business requirements change fast. In other cases DDD may bring more accidental complexity than solve.
For what it's worth, here are some additional remarks on DDD concepts that will hopefully help:
Use Case Optimal Repository Queries:
Vaughn Vernon describes a pattern Use Case optimal Repository Queries
as....
Rather than reading multiple whole Aggregate instances of various types and then programmatically composing them into a single container (DTO or DPO
), you might instead want to use what is called a use case optimal query. This is where you design your Repository with a finder query methods that compose a custom object as a superset of one or more Aggregate
instances. The query dynamically places the results into a Value Object
(DDD
) specifically design to address the needs of the use case.
You design a Value Object and not a DTO because the query is domain specific, not application specific such(as are DTOS). The custom use case optimal Value Object is then consumed directly by the view render.
This is a similar approach to using CQRS
; however, the repository is executing off your unified domain model store and not a database designed to support your read-only views.
Vaughn Vernon also states:
If you find that you must create many finder methods for supporting use case optimal queries on multiple repositories, it's probably a code smell.
This could because you misjudged the Aggregate boundaries and overlooked the opportunity to design one or more Aggregates of different types.
Vaughn describes this code smell as: Repository masks Aggregate mis-design
This could also point to the need to consider using CQRS
.
DDD Query Model (aka Read Model)
The query model is a denormalized data model. It is meant for display only data and not meant to deliver domain behavior. Vaughn Vernon states:
If this kind of data model is a SQL database, each table would hold data for a single kind of client view(display). The table can have many columns, even a subset of those needed by any given user interface display view. Table views can be created from tables, each of which is used as a logical subset of the whole.
He also states to create support for an many views as needed. It's worth noting that CQRS
-based views can be both cheap and disposable ( for development and maintenance). Using Event Sourcing
, plays nice with this approach.
DDD DTOs:
One approach is having your application layer assemble DTOs
. The DTO
would be a projection a subset of your domain entity or entities to satisfy your view.
Vaughn Vernon simply states -
DTO is designed to hold the entire number of attributes that need to be displayed in a view
DDD Repository
Martin Fowler describe the Repository pattern as:
Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.
Please reference these SO questions:
DDD: Should a Dto Assembler be a part of Domain Layer?
Should the repository layer return data-transfer-objects (DTO)?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With