If I'm using a domain model, how do I support ad hoc SQL queries?
Part of the point of a domain model is that it adds significant behavior to the data in the application. If you want reports against that data, the domain model can often do a great deal to help. However many reporting tools exist that expect to talk to a SQL database - they just can't deal with domain models. So what is one to do?
The first thing to do is to question the need for ad hoc reports. Too often a request for ad hoc reports is merely a symptom that nobody's bothered to dig into the requirements properly. By doing so you main find that the reports are rather more constrained than you thought and they can be supported perfectly well by writing code against the domain model. A lot of the time the real need is for reports to be produced quickly, the customer doesn't care how; and isn't inclined to type in SQL themselves anyway.
This isn't true in all cases. Sometimes there are power users who are happy to use some SQL based reporting tool and want to use that directly. In which case a good strategy is to produce a reporting database. Such a database is a separate database to the one that actually holds the operational data. This database is populated by code run against the domain model. and can thus insert derived data from the domain model into the reporting database. This has several advantages.
- Since it's populated via the domain model, you can derive data in the domain model and put it in the reporting database.
- You don't need to normalize a reporting database, because it's read-only.
- The structure of the reporting database can be specifically designed to make it easier to write reports.
- The development team can refactor the operational database without affecting the reporting database.
- Queries run against the reporting database won't affect the performance of the operational database.
The downside to a reporting database is that the data has to be kept up to date, timeliness may cause complications. The easiest case is when you do something like use an overnight run to populate the reporting database. This often works quite well since many reporting needs work perfectly well with yesterday's data. If you need more timely data you can use a messaging system so that any changes to the operational database are forwarded to the reporting database. This is more complicated, but the data can be kept fresher. Often most reports can use slightly stale data and you can produce special case reports for things that really need to have this second's data.
A variation on this is to use views. This encapsulates the operational data and allows you to denormalize. It doesn't allow you to separate the operational load from the reporting load. More seriously you are limited to what views can derive and you can't take advantage of behavior in a domain model.
Although I've motivated reporting databases with a domain model example, this approach is also applicable for any case where you want to encapsulate your database, which many people see as one of the purposes of a Service Oriented Architecture.
See some further discussion summarized by Eric Evans.