Eager loading with HQL

In this recipe, we'll show you how to use HQL queries to eager load the child collections of our query results.

Getting ready

Complete the Getting Ready section at the beginning of this chapter.

How to do it…

  1. Create a new folder named EagerLoadingWithHql in the project.
  2. Add a new class named Recipe to the folder:
    using NH4CookbookHelpers.Queries;
    using NH4CookbookHelpers.Queries.Model;
    using NHibernate;
    
    namespace QueryRecipes.EagerLoadingWithHql
    {
        public class Recipe : QueryRecipe
        {
            protected override void Run(ISession session)
            {
                var book = session.CreateQuery(@"
                      from Book b
                      left join fetch b.Publisher")
                     .UniqueResult<Book>();
    
                Show("Book:", book);
    
                var movies = session.CreateQuery(@"
                      from Movie m
                      left join fetch m.Actors")
                  .SetResultTransformer(
    Transformers.DistinctRootEntity)
                  .List<Movie>();
    
                Show("Movies:", movies);
            }
        }
    }
  3. Run the application and start the EagerLoadingWithHql recipe.
  4. Inspect the query log to see how the related entities have been included in the queries.

How it works…

For a detailed explanation of the eager loading mechanism, see the Eager loading with LINQ recipe. Take special note of the caveats mentioned in the There's more… section.

Eager loading in HQL is accomplished by adding the fetch qualifier to a join. In the recipe, we have used a left join, since we want the root entity, even when there are no child entities; however, fetch works equally well with standard (inner) joins.

It might be tempting to add an alias to the fetched join and perhaps use it in a where clause:

left join fetch m.Actors a
where a.Actor=:name

That is strongly discouraged though, since the where clause now acts on the same join as the fetch. Not only does that limit the fetched collection itself, so that we end up with Movie instances having invalid Actors collections. It also effectively turns the left join into an inner join. If the query requires a filter on an ActorRole property, use an extra separate join or a subquery instead.

There is one scenario where an alias on the fetch join is needed, and that is if we want to eager load even deeper:

left join fetch m.Actors a
left join fetch a.BookAboutTheRole

Just as with the Criteria and QueryOver queries, we need to process the results using the call to SetResultTransformer(Transformers.DistinctRootEntity). If we don't, we may end up with more movies in the list than we expected.

..................Content has been hidden....................

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