views:

97

answers:

3

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.

A: 

I highly recommend looking into OR (object relational) mappers that support LINQ. To name the two primary ones, LINQ to SQL and Entity Framework, both from Microsoft. I believe LLBLGen also supports LINQ now, and nHibernate has a few half-baked LINQ solutions you could try. My prime recommendation is Entity Framework v4.0, which is available through .NET 4.0 betas or the Visual Studio 2010 Beta.

With a LINQ enabled OR mapper, you can easily query for the aggregate information you need dynamically, real-time, using only your domain model. There is no need for business logic to leak into your data layer, because you generally will not use stored procedures. OR mappers generate parameterized SQL for you on the fly. LINQ combined with OR mappers is an extremely powerful tool that allows you to not only query for and retrieve entities and entity graphs, but also query for data projections on your domain model...allowing the retrieval of custom data sets, aggregations, etc. via a single conceptual model.

jrista
i already DO use an OR mapper (LinqToSql) and i already DO use criteria composition and projections. This is about database Performance, i have to query about 10000 Orders per view. Its kind of like (Select N)+1 Problem
Johannes Rudolph
+1  A: 

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.

Mike Scott
the problem is not only WHERE to calculate the totals but HOW, because when i want to calculate the total i need ALL the data, thats why i consider sort of "caching" it in the database
Johannes Rudolph
That's what I'm getting at - your intent requires that you need ALL the data, so you have to give this "hint" to your data access technology. By making the role explicit in an interface, your DAL can select the appropriate fetching strategy, lazy or eager - but I'm repeating myself - that's what I said in my answer. I'm not sure why you think it doesn't answer the question :-(
Mike Scott
i dont want to calculate the data each time again and again because it would mean i would have to load all the data from the db, what i dont want because it is hurting performance very badly! I want the data (calculated sums) sort of "cached" in the db, so i can just grab them for read only purposes. My question is how to keep the cache valid/current.
Johannes Rudolph
Ah, sorry Johannes, my mistake. I suggest you have a look a Domain Events to handle this (http://www.udidahan.com/2009/06/14/domain-events-salvation/). Whenever something happens that would update the totals, for example, you'd raise a domain event. You may be able to pass the increment in the domain event and just add that to the total, without having to recalculate.
Mike Scott
looks like a nice way. Please edit your post/make it community wiki and I'll do so and I'll mark as answer.
Johannes Rudolph
A: 

"It seems strange to me to force all the event wiring and calculation logic in the aggregate root."

That is usually a call for a «Service».

Martin R-L