I had similar problems with this when developing my model and asked this question, which, I think, could help you, especially regarding your first moment.
DDD - How to implement high-performance repositories for search .
When it comes to searching, I don’t work with a “model”, instead I have specialized search repositories that return “Consolidated” objects ... i.e. "PlanSummary". These are nothing more than information objects (they can be considered more likely as reporting) and are not used in a transactional sense - I do not even define them in my library of model classes. By creating these dedicated repositories and types, I can implement high-performance search queries that can contain grouped data (for example, PlannedTraining counts) without loading all the associations of the population in memory. When the user selects one of these summary objects in the user interface, I can then use the identifier to retrieve the actual model object and perform transactional operations and commit the changes.
So, for your situation, I would provide these specialized search repositories for all three entities, and when the user wants to perform actions against one, you always extract the aggregate of the plan to which it belongs.
Thus, you perform search queries, while maintaining your only aggregate with the required invariants.
Edit - Example:
OK, so I assume that the implementation is subjective, but this is how I processed it in my application using the TeamMember aggregate as an example. An example is written in C #. I have two class libraries:
The Model library contains an aggregate class with all invariants included, and the Reporting library contains this simple class:
public class TeamMemberSummary { public string FirstName { get; set; } public string Surname { get; set; } public DateTime DateOfBirth { get; set; } public bool IsAvailable { get; set; } public string MainProductExpertise { get; set; } public int ExperienceRating { get; set; } }
The report library also contains the following interface:
public interface ITeamMemberSummaryRepository : IReportRepository<TeamMemberSummary> { }
This is the interface that the application layer will use (which in my case will be a WCF service) and will allow implementation through my IoC (Unity) container. IReportRepository lives in the Infrastructure.Interface library, as well as the base ReportRepositoryBase. Therefore, I have two different types of repository on my system: aggregated repositories and report repositories ...
Then in another Repositories.Sql library, I have an implementation:
public class TeamMemberSummaryRepository : ITeamMemberSummaryRepository { public IList<TeamMemberSummary> FindAll<TCriteria>(TCriteria criteria) where TCriteria : ICriteria { //Write SQL code here return new List<TeamMemberSummary>(); } public void Initialise() { } }
So, in my application level:
public IList<TeamMemberSummary> FindTeamMembers(TeamMemberCriteria criteria) { ITeamMemberSummaryRepository repository = RepositoryFactory.GetRepository<ITeamMemberSummaryRepository>(); return repository.FindAll(criteria); }
Then, in the client, the user can select one of these objects and perform an action against one at the application level, for example:
public void ChangeTeamMembersExperienceRating(Guid teamMemberID, int newExperienceRating) { ITeamMemberRepository repository = RepositoryFactory.GetRepository<ITeamMemberRepository>(); using(IUnitOfWork unitOfWork = UnitOfWorkFactory.CreateUnitOfWork()) { TeamMember teamMember = repository.GetByID(teamMemberID); teamMember.ChangeExperienceRating(newExperienceRating); repository.Save(teamMember); } }