2

I'm working in a new project and I'm trying to use the Clean Architecture approach with Repository pattern. I'm using .net core 3, C#, Automapper, MediatR and Dapper.

I have these layers:

Domain (in the center, the core of all): here I have the business Entities, Aggregations and Value Objects with their validations rules and exceptions;

Application (it's around the Domain): here I'm using CQRS patterns and I have my Commands, Queries and Interfaces;

Persistence: here I have the implementations of the repositories interfaces.

I red that a repository should be responsible of the all CRUD operations relative to one table in the database. For this I want to know how I should implement the repositories for an ENTITY that is an AGGREGATION ENTITY. Should I create an AGGREGATION REPOSITORY that extract data from different tables? Or should I have a repository for each table and a SERVICE that creates AGGREGATION using more than one repository?

Thanks

  • 2
    "I red that a repository should be responsible of the all CRUD operations relative to one table in the database." This not true. You do not have to have a one-repository-to-one-table relationship. – Eric King Jan 14 at 22:56
  • @EricKing ok, but when you have AGGREGATION entity how do you do? Do you implement CRUD operations for different tables in the same repository? – Christian Cascone Jan 14 at 23:19
  • Yes. If you have an Orders repository and you need to return Orders along with their OrderDetails, then you do whatever data access you need in the Orders repository. If you never get OrderDetails without the corresponding Order, then you don't need an OrderDetails repository. No need to put an arbitrary limitation on it. – Eric King Jan 14 at 23:23
4

A good repository should abstract away the underlying database structure. An entity may have its data stored in several different tables, but your domain logic shouldn't care about that. At most, you'd have one repository for each entity in your domain, but you could also just have one repository for each aggregate root. It's up to you to decide what makes sense for your case.

For example, let's say your domain contains Order entities and OrderLineItem entities. Does it make sense in your domain to retrieve an OrderLineItem directly without the corresponding Order? If so, then you may need a repository for both entities. However, if you only access OrderLineItem entities from an Order entity, then you only need a repository for Orders. This repository would potentially query both the orders table and the order line items table to construct a complete Order with all of its OrderLineItems.

| improve this answer | |
  • OK, this is clear but there is still a doubt. Imagine if I have an aggregate root that inside has entity that I need to manipulate also out of the aggregation. In this case I'll have distinct repository for each entity. It means that in each repository I'll have a GET method to take the data from the database. But where should I put the method that I'll use to get the entire aggregation? Should I have an AGGREGATION REPOSITORY (SERVICE, FACTORY... I don't know) that use the others repositories? – Christian Cascone Jan 15 at 9:37
  • @ChristianCascone this is exactly the issue you'll keep coming across with the repository pattern in general - it defines arbitrary boundaries that become ambiguous and confusing in all but the most trivial cases. This is why I generally prefer to just define the contracts for a particular query by the client and then just write whatever query satisfies that contract. I have never seen the "repository pattern" as particularly beneficial. In fact a CRUD repository is anti-CQRS, the whole point of which is to decouple your queries from your write model. – Ant P Jan 15 at 10:33
  • @AntP I want to separate the PERSISTENCE layer from DOMAIN and I want to test my logic without a database. For this I need to define an INTERFACE in my DOMAIN layer and the implementation of this it will be in PERSISTENCE layer. To follow your advice, I should have my GetUserQueryHandler (in DOMAIN) and inside this I'll have an entity that implements IGetUserQuery (DOMAIN) that has the method to extract my data. In my PERSISTENCE layer I'll implement each of this INTERFACE, Is it correct? – Christian Cascone Jan 15 at 10:44
  • 1
    @ChristianCascone I take issue with the idea that you need interfaces in your domain to separate persistence. For example, you can make queries from an orchestration or service layer and then populate your domain with values instead of injecting your persistence into your domain. What I'm saying is that when it comes to reading data, just write whatever query you need to get the data that you need, don't try and shoehorn everything into a particular model. – Ant P Jan 15 at 10:51
  • @AntP isn't clear this for me. I'll try to explain better. You are putting another layer in the middle to do things that my APPLICATION layer does. In my APPLICATION layer I have queries and commands. All of these work with the entities of my DOMAIN layer. In the handlers of the queries and the commands I need to access to my PERSISTENCE layer to get and put data. To separate the APPLICATION from the PERSISTENCE I need interfaces otherwise my APPLICATION will be strongly coupled with the kind of the database/ORM that I'll chose to use. So the question is with CQRS how can I do this? – Christian Cascone Jan 15 at 11:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.