views:

502

answers:

2

I have implemented the command side of DDD using the domain model and repositories, but how do I implement the query side?

Do I create an entirely new domain model for the UI, and where is this kept in the project structure...in the domain layer, the UI layer, etc?

Also, what do I use as my querying mechanism, do I create new repositories specifically for the UI domain objects, something other than repositories, or something else?

+4  A: 

From my understanding of CQS you would create a set a DTOs that fulfill the requirements of the user interface screens or applications that may need to consume them.

Where this exists in the project is based on the requirements as it would depend if you were going to expose these Dtos via web services. In which case I wouldn't put it in the Web Layer but rather in the Application layer or a dedicated Facade layer.

Then you would have a read only repository or data access layer which populates the DTOs directly. I think that the Query side of things should be optimized for read performance in which case direct queries/stored procs on database views or tables and SqlDataReaders would do the best job here. But it would definetly be worth abstracting this access behind an interface so you can add a cached implementation later down the track.

If you're using an ORM and want to map from your Domain Entities to the Dtos then you could have a generic QueryRepository which has methods which take an ISpecification or similar construct for defining your queries then a DtoAssembler object for creating the Dtos from your Domain objects. Then have an implementation has a first class object for each of the queries you are going to perform.

Here's a fairly contrived example but I hope it gives you an idea.

       public interface ISpecification<T>
        {
            Expression<Func<T, bool>> Predicate { get; }

        }

       public class ActiveCustomersSpecification : ISpecification<Customer>
        {
            private Expression<Func<Customer, bool>> predicate;
            public ActiveCustomersSpecification()
            {
                predicate = c => c.IsActive; 
            }
            #region ISpecicfication<Customer> Members

            public Expression<Func<Customer, bool>> Predicate
            {
                get { return predicate; }
            }

            #endregion
        }

        public interface IQueryRepository<T>
        {
            IQueryable<T> GetQuery(ISpecification<T> specification);

            IEnumerable<T> FindAllBy(ISpecification<T> specification); 
        }



public class CustomerDtoAssembler
    {
        public CustomerDto AssembleFrom(Customer customer)
        {
            var customerDto = new CustomerDto
            {
                Id = customer.Id
            };

            return customerDto; 
        }
    }
willbt
+1  A: 

I think willbt has given you a really good starting point.

I would add that if you do opt to continue to use the ORM as the data-access strategy for queries you would be well-advised to consider defining a fetching strategy tailored to the data you expect you'll need to access (I'm thinking specifically about NHibernate here, by the way). What this means is you can decide whether to lazy-load or to eager-load the objects and collections associated with a particular Aggregate Root object.

The NCommon project by Ritesh Rao offers an excellent (work in progress) demonstration of how to define a different fetching strategy for different purposes.

Ritesh explains it really well in his blog.

Go ahead and have a look at the source:

In the test 'Repository_For_Uses_Registered_Fetching_Strategies' the call to

NHRepository<Order>().For<NHRepositoryTests>()

...causes the fetching strategies registered against the NHRepositoryTests class to be used, and therefore the OrderItems and Products will be eager loaded without messing about with NHibernate mapping configurations.

rohancragg
This is a valid point. However It only really applies if you were to return your Entities to your Facade layer and then map to DTOs. My suggestion here would be to use the returned IQueryable and project directly into the DTOs. This way you avoid any FetchStrategies. You can even do projection at NHibernate mapping level as well.
willbt
Of course! Yes, thanks. I'm still coming to terms with how having NHibernate.Linq changes the game, but if you look at how Ritesh is embracing IQueryable you'll see he certinaly 'gets it' and is building good things around it (i.e. Specifications that take an Expression in their constructor).
rohancragg
links now updated to GitHub locations
rohancragg