Using Futures

We've learned to use MultiCriteria and MultiQuery to batch our queries together. NHibernate's Futures feature provides a simpler API for batching criteria and queries. In this recipe, we'll show you how to use NHibernate's new Futures feature to return a paged product result. Both LINQ and HQL are used in the same method, to show the syntactic difference but also that they can work together.

Getting ready

Complete the Getting Ready instructions at the beginning of Chapter 4, Queries.

How to do it...

  1. Add a new folder named Futures to the QueryRecipes project.
  2. Add a new struct named PageOf to the folder:
    using System.Collections.Generic;
    
    namespace QueryRecipes.Futures
    {
        public struct PageOf<T>
        {
            public int PageCount;
            public int PageNumber;
            public IEnumerable<T> PageOfResults;
        }
    }
  3. Add a new class named Queries to the folder:
    using System;
    using System.Linq;
    using NH4CookbookHelpers.Queries.Model;
    using NHibernate;
    using NHibernate.Linq;
    
    namespace QueryRecipes.Futures
    {
      public class Queries
      {
        private readonly ISession _session;
    
        public Queries(ISession session)
        {
          _session = session;
        }
    
        public PageOf<Product> GetPageOfProducts(
    int pageNumber,
    int pageSize)
        {
          var skip = (pageNumber - 1) * pageSize;
    
    var productCount = _session.Query<Product>()
    .ToFutureValue(x=>x.Count());
          
          var products = GetPageQuery(skip, pageSize)
    .Future<Product>();
    
    
          var pageCount = (int)Math.Ceiling(
          productCount.Value / (double)pageSize);
    
          return new PageOf<Product>()
          {
            PageCount = pageCount,
            PageOfResults = products,
            PageNumber = pageNumber
          };
        }
        
        private IQuery GetPageQuery(int skip, int take)
        {
          var hql = @"from Product p order by p.UnitPrice asc";
          return _session.CreateQuery(hql)
          .SetFirstResult(skip)
          .SetMaxResults(take);
        }
      }
    }
  4. Add a new class named Recipe to the folder:
    using NH4CookbookHelpers.Queries;
    using NHibernate;
    
    namespace QueryRecipes.Futures
    {
      public class Recipe : QueryRecipe
      {
        protected override void Run(ISession session)
        {
          var queries = new Queries(session);
          var result = queries.GetPageOfProducts(1, 2);
          var heading = string.Format("Page {0} of {1}",
          result.PageNumber,
          result.PageCount);
          Show(heading, result.PageOfResults);
        }
      }
    }
  5. Run the application and start the Futures recipe.

How it works...

In this recipe, we will use the Futures syntax to retrieve a count of all the products, along with a page of products for display.

When we call IQuery, ICriteria instance Future, or FutureValue, NHibernate returns an object representing the potential results of that query. It also queues up the query in a hidden MultiCriteria or MultiQuery inside the session. The same thing happens for a LINQ query when ToFuture or ToFutureValue is used. The naming difference is purely a matter of following LINQ's naming conventions.

When we call FutureValue, it returns an IFutureValue<>, representing a single entity or scalar value. For Future, it returns an IEnumerable<>. NHibernate waits until we access the Value property of IFutureValue<> or enumerate the IEnumerable. When we do, NHibernate executes all the postponed Futures for this session.

In this specific example, both queries are executed when we use productCount.Value to calculate the page count. As you can see, this deferred loading is mostly transparent to the application.

There's more...

The two minor caveats while using Futures are as follows:

  • An attempt to load the results of a Future query after the session has been closed and it will throw an exception.
  • While the syntax is identical, ICriteria and IQuery objects are handled separately in the session. If you have an ICriteria and an IQuery based Future, evaluating one will not execute the other.

See also

  • Using Criteria Queries
  • Using QueryOver
  • Using MultiCriteria
  • Using the Hibernate Query Language
  • Using MultiQuery
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.12.50