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.