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.
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 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 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>();
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.
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.