Consider the Following object model (->> indicates collection):
Customer->Orders
Orders->>OrderLineItems->Product{Price}
The app is focused on processing orders, so most of the time tables showing all the orders that match certain criteria are used in the UI. 99% of the time i am only interested in displaying the Sum of LineTotals, not the individual LineTotals.
Thinking about it further, there also might be multiple payments (wire transfers,cheque, credit card etc.) associated with each order, again, im only interested in the sum of money that i received.
When querying the database for an order, I dont want to select all orders and then, for each order, its payments and LineItems.
My idea was to store the associate each order with a “status” object, caching all the sums and status of an order, improving query performance by orders of magnitude and also supporting query scenarios for unpaid orders, paid orders, orders due etc.
This prevents domain logic (e.g. when an order is considered to be paid) from leaking into database queries. However, it puts the responsibility for keeping the sums up to date. The system usually has well defined points where that needs to happen, e.g. entering or integrating payments, creating/modifying an order.
So far i have used Observable Collections, that trigger recalculations of Status when items are added or removed, or certain properties on the items are updated. I ask myself where the logic for all that should be put from a ddd perspective. It seems strange to me to force all the event wiring and calculation logic in the aggregate root.
You need to express the intent of a request in an intention-revealing interface, so that your repositories can understand what exactly you want to do and react accordingly. In this case the interface reveals intent, not to other developers, but to other code. So if you want a status or total, create an interface that reveals this intent and request an object of that type from your repository. The repository can then create and return a domain object which encapsulates doing exactly the work required to calculate the total and no more than that.
In addition, your DAL can intelligently choose which fetching strategy to apply from the interface you request, i.e. lazy loading for situations where you don’t need to access child objects and eager loading where you do.
Udi Dahan has some great blog posts about this. He has written and talked on applying intention-revealing interfaces to this problem, which he calls making roles explicit.