Eager fetching

You can disable lazy loading in mapping and that would load all collections/associations eagerly all the time. But as stated earlier, eagerly loading associations all the time is not a good idea. However, at times you do need to load a particular association eagerly. For this reason, NHibernate lets you specify, during the query, that a particular association should be loaded eagerly. Let's take a look at examples of different querying mechanisms to see how to eagerly load associations.

HQL

To eagerly load associations in HQL, you need to add keyword fetch after the join keyword, as shown next:

select e from Employee as e join fetch e.Benefits where e.Firstname = :firstName

Preceding HQL query loads all employee instances with matching first name and also loads their Benefits collection in the same select eagerly.

Criteria

Criteria API offers a method named SetFetchMode that can be used to tell NHibernate of our intent to load a particular association eagerly. Following example loads employee records having first name as John and also loads the Benefits collection eagerly in the same SELECT statement:

var employees = Database.Session.CreateCriteria<Employee>()
                    .Add(Restrictions.Eq("Firstname", "John"))
                    .SetFetchMode("Benefits", FetchMode.Join)
                    .List<Employee>();

SetFetchMode takes two parameters. First is the name of the association property for which fetch mode is specified. Second parameter is the actual fetch mode specified using the FetchMode enum. The FetchMode enum has following values:

  • Default: Default is Select.
  • Lazy: Load the association lazily. This will use a separate SELECT statement to load the association when accessed.
  • Eager: Load the association eagerly. This will use left outer join to load the association at the same time as root entity is loaded.
  • Select: Same as Lazy.
  • Join: Same as Eager.

QueryOver

QueryOver offers a nice lambda syntax for eager loading of associations. Following code listing shows the previous query written using QueryOver:

var employees = Database.Session.QueryOver<Employee>()
.Where(x => x.Firstname == "John")
.Fetch(e => e.Benefits).Eager.List<Employee>();

The Fetch method takes in a lambda to which you can pass the association property that you want to load eagerly followed by a call to Eager. This also works in the opposite way. If the association has laziness disabled and you want to load the association lazily in this query, then you can call Lazy after the call to the Fetch method, as shown next:

.Fetch(e => e.Benefits).Lazy

If you want to eagerly fetch more than one association/collection, you just need to repeat the call to the Fetch method, passing association/collection that you want fetched eagerly. Following fetches both Benefits and Communities eagerly:

var employees = Database.Session.QueryOver<Employee>()
                    .Where(x => x.Firstname == "John")
                    .Fetch(e => e.Benefits).Eager
                    .Fetch(e => e.Communities).Eager
                    .List<Employee>();

Although it is not recommended to load multiple levels of objects eagerly, if there is a requirement to do so, then that is supported as well. If you want to eagerly fetch the Communities collection and then eagerly fetch the Members collection that is present on the Communities collection, then you can do it as follows:

var employees = Database.Session.QueryOver<Employee>()
.Where(x => x.Firstname == "John")
.Fetch(e => e.Communities).Eager
.Fetch(e => e.Communities.First().Members).Eager.List<Employee>();

LINQ

Similar to QueryOver, LINQ offers a Fetch method that can be used to eagerly load associations/collections. But unlike QueryOver, this method can only be used to eagerly load associations/collections that would have been otherwise loaded lazily. Following is the same query written using LINQ:

var employees = Database.Session.Query<Employee>()
                    .Where(x => x.Firstname == "John")
                    .Fetch(e => e.Benefits)
                    .ToList();

Unlike QueryOver, there is no need to call anything after call to the Fetch method. If you need to eagerly load multiple collections then just place call to Fetch multiple times.

LINQ also has a FetchMany method which needs an explanation. While Fetch is capable of eagerly loading both single-ended associations and collections, FetchMany only deals with collections. But if you intend to eagerly fetch child association/collection on the collection that you have loaded eagerly, then you must use FetchMany. Let's look into an example. If we want to eagerly load the Communities collection on Employee and then eagerly load the Members collection on that Communities collection, then we must use FetchMany, as shown next:

var employees = Database.Session.Query<Employee>()
                    .Where(x => x.Firstname == "John")
                    .FetchMany(e => e.Communities)
                    .ThenFetch(c => c.Members);

Note the ThenFetch call that we are seeing for the first time. The ThenFetch method is used to tell NHibernate that association/collection from second level also needs to be loaded eagerly.

Note

Selective eager loading in queries looks like a good option to disable lazy loading temporarily. But there is a flip side to this approach. The SQL that is generated for eager loading may be Cartesian product of tables involved. Cartesian products are not very good at performance and may return more number of records than we expect by giving duplicate entities in the result. Future queries come in handy if want eager loading without side effects such as Cartesian products. We will look at future queries in the next chapter.

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

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