Skip to content

Using Query Objects

seif edited this page Jun 17, 2012 · 7 revisions

Recipe #001 - Using Query Objects

Overview

Inspiration: CQRS a la Greg Young

Query Objects and their contracts live in the Presentation Layer and are used to populate viewmodels. This accomplishes two objectives: getting rid of populating viewmodels in the Controllers as Controllers are meant to orchestrate, and keeping simply queries out of higher layers, such as Tasks.

Example implementation

Query Object

public class ProductsListQuery : NHibernateQuery, IProductsListQuery
{
    public IPagination<ProductViewModel> GetPagedList(int page, int size)
    {
        var query = Session.QueryOver<Product>().OrderBy(x => x.Name).Asc;

        var count = query.ToRowCountQuery();
        var totalCount = count.FutureValue<int>();

        var firstResult = (page - 1) * size;

        ProductViewModel viewModel = null;
        ProductCategory categoryAlias = null;
        
        var viewModels =
           query.JoinAlias(x => x.Category, () => categoryAlias)
                .SelectList(list => list
                                     .Select(x => x.Id).WithAlias(() => viewModel.Id)
                                     .Select(x => x.Name).WithAlias(() => viewModel.Name)
                                     .Select(x => x.ProductNumber).WithAlias(() => viewModel.ProductNumber)
                                     .Select(x => x.ListPrice).WithAlias(() => viewModel.ListPrice)
                                     .Select(x => x.SellStartDate).WithAlias(() => viewModel.SellStartDate)
                                     .Select(x => x.SellEndDate).WithAlias(() => viewModel.SellEndDate)

                                     // Flattening the object graph
                                     .Select(x => categoryAlias.Name).WithAlias(() => viewModel.CategoryName))
            .TransformUsing(Transformers.AliasToBean(typeof(ProductViewModel)))
            .Skip(firstResult)
            .Take(size)
            .Future<ProductViewModel>();

        return new CustomPagination<ProductViewModel>(viewModels, page, size, totalCount.Value);
    }
}

Contract

public interface IProductsListQuery
{
    IPagination<ProductViewModel> GetPagedList(int page, int size);
}

Controller

    public ActionResult Index(int? page)
    {
        var viewModel = new ProductsListViewModel
                            {
                                Products = this.productsListQuery.GetPagedList(page ?? 1, DefaultPageSize)
                            };
        return View(viewModel);
    }