Reputation: 3127
I have recently started exploring Domain driven design and have a question. Suppose I have a Product, Category, Manufacturer domain models in my application. And Product looks like this:
public class Product
{
int ProductId;
string Title;
string Description;
double Price;
int CategoryId;
Category Category;
Manufacturer Manufacturer;
}
Generally on a detail view where a product is displayed, Category Name and Manufacturer name is shown (rather than their Ids). But Category and Manufacturer are different Aggregates. Question is how to fetch Manufacturer and Category Name along with Product Domain Model. ProductRepository will only return Product domain Model (along with categoryId and ManufacturerId).
But I don't need all the attributes, I just need their title. And I am facing similar issues with all the domain model.
Please help how should I solve this problem.
Upvotes: 2
Views: 176
Reputation: 15727
Generally on a detail view where a product is displayed, Category Name and Manufacturer name is shown (rather than their Ids). ... Question is how to fetch Manufacturer and Category Name along with Product Domain Model. ProductRepository will only return Product domain Model (along with categoryId and ManufacturerId)
As I see, Category Name and Manufacturer Name are used for displaying so it is presentation concern. I'd suggest having a separate read model for Product which serves that screen only (see Command Query Responsibility Segregation (CQRS)):
public class ProductReadModel
{
int ProductId;
string Title;
string Description;
double Price;
string CategoryName;
string ManufacturerName;
}
There are different ways to fill/build that model:
If our aggregates are persisted in relational data base using ORM (e.g. NHibernate) then you can directly query your data base using raw SQL or a light-weight ORM (e.g. Dapper). You do not need repository for it, you need just QueryHandler
If our aggregates are event sourced, then you simply listen to Domain Events (e.g. CategoryNameChanged
/ManufacturerNameChanged
) and then project (denormalise) them into ProductReadModel
and store it in any storage (even in memory).
You can also fire and project/denormalise Domain Events if your aggregates are persisted in relational data base.
Upvotes: 0
Reputation: 795
In addition to @tomliversidge's answer I recommend looking into the Composite UI pattern (you can find an example here).
There you would have a Service Gateway building a composite View Model consisting of information from the 3 services (Product, Manufacturer and Category).
Upvotes: 0
Reputation: 2369
There are various ways you can handle this:
Local Caching / View Models
Keep an in-memory cache locally in your service that maps between CategoryId and CategoryTitle (same for Manufacturer) - this can either be through:
Denormalising the data
You could duplicate the data by saving the CategoryTitle alongside the CategoryId. This way you have no call to an external service. The tradeoff is you need to consider how often the CategoryTitle is likely to change, and how you handle that change.
Reporting "domain"
You could have a completely separate service that listens for data from other services and maintains view models for UIs. This would keep your other services ignorant of other service's concerns. When using an event-driven system, you'd be listening for events form other services that allow you to build a view model for the UI
Upvotes: 2