views:

1418

answers:

4

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).

+1  A: 

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.

NerdFury
I see what you mean about two separate classes to make the separation explicit and I agree. But if I'm only querying in order to create DTOs, do I really want to use an ORM for that? I don't need change tracking or unit of work. I like the projections/mapping but my Query-side DTOs have nothing to do with my command object graph, and the queries are sometimes complex - easier to write in a View or stored proc than in HQL or using Criteria. What about create views for the Query DTOs? Fine for some, but all? and I'm not sure I want to map across n-tables in NHib just to grab a DTO. THX.
lordinateur
I see your point, I've certainly struggled to get HQL to do what I want when joining a few tables. I guess, if you have an interface that defines the methods you are using to query, in the end the implementation doesn't matter. Code to the interface, and use what makes sense. Maybe it's a mix of Nhibernate, and ADO.NET, or all ADO.NET. If you find a weakness with your choice later one, implement a new concrete class using the technology that makes sense. This is a scenario where you certainly know best what is right, and sounds like the ORM doesn't add anything in your scenario.
NerdFury
+3  A: 

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.

Daniel Auger
Yes, I do mean CQRS. I think the architectural approach makes a lot of sense, and I would like to use the ORM for the reasons you give. But how would you address the issues I raised about complex DTO mappings? For example, I need to flatten hierarchical and many-to-many relationships that are dependent on types in an inheritance tree. I know that's vague but just assume that NHibernate (or any ORM) mapping is nasty in these cases. Would you map to a stored proc or view at that point, or what?
lordinateur
Forgive me if you already are aware of this: NH can map from views and procs. Therefore, you can use a view or proc in DB, but still have the retrieval / query go through NH.
Daniel Auger
Yes, that's where I'm leaning - mapping to views and/or procs. I suppose one can think of views/procs as the read-only db model. This is what I think of as poor man's denormalization. In CQRS, you might push these views into tables in read-slaves, but for the time being, they are simply implemented as views. Maybe that's the best way to think about it.
lordinateur
The approach we use is exactly as described: we use views to represent denormalized data structures which we then query directly with nhibernate. I do hate they we have to maintain views in our data model, but it works well.
Joseph Daigle
+1  A: 

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.

deadbeef
+2  A: 

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.

Charlie Flowers
How do you handle inserts/updates to your read tables? Do you use messaging?
lordinateur
Yes, we use nServiceBus, and the domain objects publish events when writes occur. A Subscriber to those events then populates the Query database.
Charlie Flowers
Gem of the day. Didn't like active record pattern before, but with cqrs it really makes sense. Thanks.
Arnis L.