NHibernate returning filtered result containg data computation

Roland, 16.05.2016

Recently I needed a query with some computation made in SQL. But the difficulty was that the computation wasn't just an a + b statement. It was supposed to aggregate number of items underlying in my domain object with some extra conditions.

Suppose I have entity Order that looks like:

    public class Order
    {
        private List<OrderItem> items;

        public Order()
        {
            items = new List<OrderItem>();
        }

        public virtual int Id { get; protected set; }

        public virtual DateTime DateCreated { get; set; }

        public virtual IEnumerable<OrderItem> Items
        {
            get { return items; }
        }
    }

Then the OrderItem:

    public class OrderItem
    {
        public virtual int Id { get; protected set; }

        public virtual Article Article { get; set; }

        public virtual int Quantity { get; set; }

        public virtual decimal Price { get; set; }
    }

The Article property and Article entity are not important in this context so no sorce code for now.

What I needed exactly was: orders (OrderDto) created after date 2016-01-01 having at least one item that has the quantity greater than 100.0

The query (QueryOver) I needed looks like:

            var date = new DateTime(2016, 1, 1);
            var session = sessionFactory.GetCurrentSession();

            Order _this = null;
            OrderItem item = null;
            OrderDto dto = null;
            var result = session.QueryOver<Model.Order>(() => _this)
                .Left.JoinAlias(() => _this.Items, () => item,
                    NHibernate.Criterion.Restrictions.Gt(
                        NHibernate.Criterion.Projections.Property(() => item.Quantity),
                        100))
                .SelectList(l => l
                    .Select(() => _this.Id).WithAlias(() => dto.Id)
                    .Select(() => _this.DateCreated).WithAlias(() => dto.DateCreated)
                    .SelectGroup(() => _this.Id)
                    .SelectGroup(() => _this.DateCreated)
                    .SelectCount(() => item.Id).WithAlias(() => dto.ItemCount))
                .Where(
                    NHibernate.Criterion.Restrictions.Gt(
                        NHibernate.Criterion.Projections.Count(
                            NHibernate.Criterion.Projections.Property(() => item.Id)),
                        0))
                .Where(
                    NHibernate.Criterion.Restrictions.Gt(
                        NHibernate.Criterion.Projections.Property(() => _this.DateCreated),
                        date))
                .TransformUsing(
                    Transformers.AliasToBean<OrderDto>())
                .List();

Which resulted with SQL:

    SELECT
        this_.Id as y0_,
        this_.DateCreated as y1_,
        this_.Id as y2_,
        this_.DateCreated as y3_,
        count(item1_.Id) as y4_ 
    FROM
        "Order" this_ 
    left outer join
        "OrderItem" item1_ 
            on this_.Id=item1_.Order_id 
            and (
                item1_.Quantity > @p0 
            ) 
    WHERE
        this_.DateCreated > @p1 
    GROUP BY
        this_.Id,
        this_.DateCreated 
    HAVING
        count(item1_.Id) > @p2;

The SQL above looke pretty much what I needed.

The example shows how to compute some data with non trivial restrictions (conditions) in a query instead of post query computation in C#.