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, I'll show you how to use NHibernate's new Futures feature to return a paged product result.

How to do it...

  1. Complete the setup steps in the introduction at the beginning of this chapter, naming the new console application PagingResults.
  2. Add a new mapping document named CountAllProducts.hbm.xml with the following xml code. Don't forget to set the Build action to Embedded Resource.
    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
      <query name="CountAllProducts">
        <![CDATA[
        select count(p.Id) from Product p
        ]]>
      </query>
    </hibernate-mapping>
  3. Add another mapping document named GetAllProducts.hbm.xml and set the Build action to embedded resource. Use the following xml:
    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
      <query name="GetAllProducts">
        <![CDATA[
        from Product p order by p.UnitPrice asc
        ]]>
      </query>
    </hibernate-mapping>
  4. In App.config, add <mapping assembly="PagedResults"/> below the mapping element for Eg.Core.
  5. Add the following structure inside the Queries class:
    public struct PageOf<T>
    {
      public int PageCount;
      public int PageNumber;
      public IEnumerable<T> PageOfResults;
    }
  6. Add the following method to the Queries class:
    public PageOf<Product> GetPageOfProducts(
      int pageNumber,
      int pageSize)
    {
      var skip = (pageNumber - 1) * pageSize;
    
      var productCount = 
        _session.GetNamedQuery("CountAllProducts")
        .FutureValue<long>();
    
      var products = 
        _session.GetNamedQuery("GetAllProducts")
        .SetFirstResult(skip)
        .SetMaxResults(pageSize)
        .Future<Product>();
    
      var pageCount = (int) Math.Ceiling(
        productCount.Value/(double) pageSize);
    
      return new PageOf<Product>()
               {
                 PageCount = pageCount,
                 PageOfResults = products,
                 PageNumber = pageNumber
               };
    }
  7. In Program.cs, use the following code in the RunQueries method:
    static void RunQueries(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);
    }
  8. Build and run your application. You should see the following output:
    How to do it...

How it works...

In this recipe, we are using the simpler Futures syntax to again retrieve a count of all products, along with a page of products for display.

When we call IQuery or ICriteria's 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.

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 Value property of IFutureValue<> or enumerate the IEnumerable. When we do, NHibernate executes the hidden futures MultiCriteria and MultiQuery 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 delayed loading is mostly transparent to the application.

There's more...

The two minor caveats when using futures are as follows:

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

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