I have an issue with how to design aggregates.
I have Company
, City
, Province
and Country
entities. Each of these needs to be an aggregate root of its own aggregate. The City
, Province
and Country
entities are used throughout the system and are referenced by many other entities, so they are not value objects and also need to be accessed in many different scenarios. So they should have repositories. A CityRepository
would have methods such as FindById(int)
, GetAll()
, GetByProvince(Province)
, GetByCountry(Country)
, GetByName(string)
.
Take the following example. A Company
entity is associated with a City
, which belong to a Province
which belongs to a Country
:
Now let's say we have a company listing page which lists some companies with their city, province and country.
Reference by ID
If an entity needs to reference a City
, Province
or Country
, they would do so by ID (as suggested by Vaughn Vernon).
In order to get this data from the repositories, we need to call 4 different repositories and then match up the data in order to populate the view.
var companies = CompanyRepository.GetBySomeCriteria();
var cities = CityRepository.GetByIds(companies.Select(x => x.CityId);
var provinces = ProvinceRepository.GetByIds(cities.Select(x => x.ProvinceId);
var countries = CountryRepository.GetByIds(province.Select(x => x.CountryId);
foreach(var company in companies)
{
var city = cities.Single(x => x.CityId == company.CityId);
var province = provinces.Single(x => x.ProvinceId == city.ProvinceId);
var country = countries.Single(x => x.CountryId == province.CountryId);
someViewModel = new CompanyLineViewModel(company.Name, city.Name, province.Name, country.Name);
}
This is a very bulky and inefficient, but apparently the 'correct' way?
Reference by Reference
If the entites were referenced by reference, the same query would look like this:
var companies = CompanyRepository.GetBySomeCriteria();
someViewModel = new CompanyLineViewModel(company.Name, company.City.Name, company.Province.Name, company.Country.Name);
But as far as I understand, these entities cannot be referenced by reference as they exist in different aggregates.
Question
How else could I better design these aggregates?
Could I load company entities with the city model even when they exist in different aggregates? I imagine this would soon break the boundaries between aggregates. It would also create confusion when dealing with transactional consistency when updating aggregates.