How entities covered with in an aggregate Root are saved in DDD?

4.4k Views Asked by At

After reading lot of posts, I realised if an aggregate root exists for a concept/context, we need to have a single repository for that whole concept/context.

If thats the case, I see there won't be any repositories for the internal entities. If so, how these internal entities are saved to database?

I have a many internal entities under the aggregate root. So, wondering If I need to have all the saving of the internal entities under the aggregate root repository, it's going to be bloated. Please suggest what can be done in this case.

Also, my internal entities will go to each table of their own at the persistence level. Please correct me if I'm not allowed to store internal entities this way.

Example
Consider I have a Restaurant as a aggregate root. It can group an entity named Review. A review exists for a restaurant and can’t exist without it.

Here if Review is an internal entity and there can be numerous reviews for a restaurant, Reviews will be saved in a separate table. But as there will be only one Restaurant Repository for Restaurant aggregate root, how/where to handle saving reviews.

3

There are 3 best solutions below

1
CPerson On

If thats the case, I see there won't be any repositories for the internal entities. If so, how these internal entities are saved to database?

An Aggregate represents a consistency boundary. If an Entity is owned by an Aggregate and is required for ensuring consistency then it should be persisted with the Aggregate Root.

So, wondering If I need to have all the saving of the internal entities under the aggregate root repository, it's going to be bloated.

Yes, it would be. You can consider using an ORM if this is a real issue. The ORM will maintain in memory the graph rooted at your Aggregate Root and will ensure that changes are persisted as necessary.

Also, my internal entities will go to each table of their own at the persistence level. Please correct me if I'm not allowed to store internal entities this way.

Try to think of your domain separately from your persistence strategy. You have a domain model that you map into a relational schema. The relational schema should not drive the design of the domain.

9
Alexey Zimarev On

I'd like to complement the answer by CPerson.

Such discussions without going to the context are often meaningless. Each case is context-specific and it rarely boils down to an issue with persistence.

In the mentioned case, I would never model Review as an entity in the Restaurant aggregate. It is not a persistence issue, it is a modelling issue.

There are a few DDD books out there and I believe that reading a few blog posts isn't enough to understand both strategic and tactical patterns of DDD. One of those patterns is indeed the Aggregate pattern. In short, an Aggregate is the consistency boundary. Aggregate is always context-specific (just as anything else).

If you are modelling a restaurant management system or a food delivery system, reviews would probably be in a separate context. There's no such context as the "restaurant context". That's the whole point of the Bounded Context pattern. In your example, it is, probably, the restaurant review context. What happens with reviews has nothing to do with food, opening hours and table bookings.

If you are modelling something like TripAdviser, you only have reviews, basically. In such a case, reviews are more or less agnostic to what is being reviewed. Then, your model is completely different.

The number of reviews is ever-growing, so putting all reviews as entities to some aggregate won't make much of a sense. Again, Aggregate is the consistency boundary. Would you say that a review cannot be posted if another review is one star? I don't think so. What is the invariant that you're trying to protect in the Restaurant aggregate, concerning reviews? Would you need to limit the reviews count of change the state of a Restaurant based on those reviews? I don't think it's the case. So, a review could be an aggregate on its own, since all reviews are completely independent of each other.

A Restaurant in the review aggregate could be a simple value object that holds the restaurant id. On the construction of this value object, you'd ensure that the given restarant indeed exists and open for reviews. You would indeed be required to clear reviews when the restaurant disappears. But it is also context-specific. The restaurant might close but you keep the reviews anyway.

4
niekname On

I agree with some of the points made in other answers about that you probably would not want to model it like that, but I think your question itself has not been answered yet. And for an example it is perfectly fine.

So here goes:

You don't create repositories (as in DDD repositories) for entities, only for the aggregate root. So in your example the application layer could be something like:

Restaurant restaurant = restaurantRepository.findById(23)
restaurant.addReview(review)
restaurantRepository.save(restaurant)

Notice also that actions are done on the aggregate root. So in general, commands in your application layer would normally be: load aggregate, execute action on it, save it

The aggregate is saved as a whole and the entities with it. What happens behind the repository is dependant on your infrastructure. And of course since the repository belongs in the domain, we don't care about that infrastructure there.

So then the implementation in the infrastructure layer (these are just some examples of how it could be):

  1. In a documentDB you would have an implementation of the repository which just saves the document to the DB as a whole. (Document stores and DDD match really well here since aggregate = document)
  2. If you were to serialize your aggregate to disk in a simple text file, you might have a repository implementation with a serializer per entity, value object to do the serialization.
  3. If you have an RDBMS you would indeed want the entities to be stored in their own table. Here you could use:

    • An ORM framework and just save the root entity and let the framework automatically save / delete / update the child entities
    • Use a DAO pattern and create a DAO per table / entity
    • ...

Also have a look at this question

Also, in some cases it can happen that you would split up an aggregate for technical reasons only. If you were to have an aggregate with tons of entities and it gets to heavy to handle it well, then you might want to split it in two aggregates purely for technical reasons. But that is something that you try to avoid and only do when really necessary.