Question

I'm trying to learn about DDD and there's a thing about the entities and repositories that I'm unable to understand.

From other questions here on SO I realized it is a bad habit to inject Repositories into Entities. But how to avoid injecting repository when I'm composing objects?

Let's have simple situation - events and events application. This seems simple.

$event->add($application);
$eventRepository->save($event);

I believe the $application is an Entity so I believe there should be some $applicationRepository.

Does it mean, that I should inject $applicationRepository to $eventRepository to save the Event entity? Like

class eventRepository {

    ...

    public function save(Event $event) {
        ...

        foreach ($event->applications as $app) {
            $this->applicationRepository->save($app);
        }

        ...
    }
}

Another solution that came to my mind is this:

$eventService->addAplication($event, $application);

class $eventService {

    ...

    public function addApplication(Event $event, Application $app) {

        // simple example of validation, something like $event->isAplyable()
        if ($event->capacity > count($event->applications)) {
            $this->applicationRepository->save($app);
            $event->addApplication($app);
        }

    }
}

Is one method better than the other? Or did I completely messed it up?

Was it helpful?

Solution

One way to avoid an explicit call to an application repository is for the event repository to persists application instances that are associated with a given event. This is essentially the first option you propose, however depending on the persistence framework you use, the code could look a little different. For instance, some ORMs support persistence by reachability which means that if you're persisting an event and the frameworks finds transient application instances reachable from the event, it will persist those too. In this case there is not need for an explicit application repository.

The idea at play here is that of aggregate roots. If an Event is an aggregate root and an Application is a constituent value object, then the event repository must be able to persist the entire object graph, including the associated application instances. DDD suggests one repository per aggregate root not necessarily per-entity.

It may be the case that both Event and Application are aggregate roots (ARs). In that case it is not advised to have direct object references between ARs, but to instead use identity references. In that case, your second example would apply, except in a slightly different form. The event service should be an application service which hosts specific use cases associated with events. One of those is adding an application. The difference is that the addApplication method should accept an event ID and application ID as arguments which it would then load from the respective repositories. It would also be able to explicitly persist both events and applications using their respective repositories.

Take a look at Effective Aggregate Design by Vaughn Vernon for ideas on how to determine ARs in your domain.

OTHER TIPS

You should have a repository per aggregate root only, and they should work independently.

So there are two scenarios that I can see, and which you choose depends on how the business does things:

  1. If the application and the event are two different aggregate roots (can one application be added to multiple events and should all the events then reference the same entity?), they should be tied together data-wise using references, so that when you save the event, it will not save the applications, but only references to the applications that it holds.

  2. If the event is the aggregate root and the application is something that lives, dies and changes with it (and they share consistency boundaries) your event repository should be able to save the application as a part of the event. Now you don't say how you persist data, but an ORM can help you with that.

Hope that helps a little. And feel free to ask.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top