Question

The principle behind the CQS architectural pattern is that you separate your queries and commands into distinct paths. Ideally, your persistence store can be read/write partitioned, but in my case, there is a single, normalized database.

If you are using an ORM (NHibernate in my case), it's clear that the ORM is used when issuing commands. But what about all the various queries you need to run to shape data (DTOs) for user screens, is it common practice to ditch the ORM when doing the Query side of CQS?

Where should I implement my queries and DTO projections? Straight ADO.NET (datareaders, dtos, datatables, stored procs)? Some queries are quite unique and involve a lot of joins to pull everything together. I don't want to denormalize the database for the queries, but I could create views (poor man's denormalization).

Was it helpful?

Solution

I'm assuming by CQS you mean the DDD architectural pattern aka CQRS, not strictly the traditional CQS principle.

I'd still use NHibernate for your read only model. There are many advantages such as future and multi queries, lazy/eager loading etc... that will optimize DB chattiness. Additionally, it will be easier to compose queries with an ORM if the UI allows for the user to essentially change the where clause.

Regarding how to technically handle a read only model, you can mark an entity immutable with NHibernate. You could simply mark all of your read model entities immutable. Also, I don't think you can update projections in NHibernate so that is another option to go for as your read only model (Someone please correct me if I am wrong as I am not 100% sure).

Regarding ugly or impossible NH mappings: NH can map to views and stored procedures, so I think it would be fine to use these when you need to. Views are probably a bit more flexible than stored procedures for a read only scenario because your SQL will still be dynamic. However, If you need read / write for any of these flattened structures I'd map to a store procedure.

OTHER TIPS

Ultimately, the idea is that you should use whatever makes the Query channel easiest for you to build and maintain. You no longer have to worry about updates, enforcing business rules, maintaining data integrity, or even handling load (for the most part). So you're free to choose many options that were previously not on the table.

But NHibernate can still be a good option ... it's just no longer the automatic default (which it sometimes is for the Command side).

We've chosen to use Castle Active Record (which is based on NHibernate under the hood), mainly because it has a nice feature that will generate a table for you from a class. This fits excellently for us, because here's our workflow: First, we create a ViewModel class. This class is shaped entirely for the needs of the View. Then, we mark that ViewModel with Castle Active Record attributes. Then, we ask Active Record to generate the corresponding table for that class in the Query database. This is the fastest, smoothest way we have found to quickly get a Query database table that serves the ViewModel class. The automatic generation reflects the reality that the only reason the table exists is to serve the view.

We're using EF for the command part, and straight ADO.NET => DTOs for query chain. Advantages:

1) Ability to optimize SQL queries and use advanced DB store features not abstracted into ORM layer

2) Less overhead

But we're using the separation only for demanding parts (search), the rest relies on common Entity Framework model.

There isn't a need to use a different approach to reading your database vs. updating your database. CQS simply states that commands that update the data store should be separate from the queries that read state from the data store.

You can still use NHibernate to read from your data store, but you might want to make it obvious by creating two different classes to encapsulate your data access. One class would have methods to read (query) the data store, the other class would have methods to issue commands (add, update, delete) to the data store.

What you are trying to avoid is a method that gets a message from the database, and then marks the message as read in the database. This should be two distinct method calls. You should not change the state and return a value from the same method.

I like to keep ORM's separate for reads and writes so I would use (and I use):

Nhibernate for commands - beautifully maps my domain model

Dapper.net for queries - beautifully maps my DTO's and allows felxibility if the query is too complex.

They are a perfect couple just like Han Solo and Chewbacca.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top