Thursday, March 1, 2012

NHibernate eager fetching

NHibernate supports the concept of eager fetching for a long time. However there are some things to consider when you start using this with the out-of-the-box NHibernate Linq provider.
Let’s first look at the obvious way:
var customers = session
.Query<Customer>()
.Fetch(c => c.Orders)
.ToList();

This will return the customer and all the customer’s orders in a single SQL statement.
Rule #1: Fetch() statements must always come last.
If you want to mix Fetch with other clauses, Fetch must always come last. The following statement will throw an exception:
var customers = session
.Query<Customer>()
.Fetch(c => c.Orders)
.Where(c => c.CustomerId == "ABC")
.ToList();

But this will work fine:

var customers = session
.Query<Customer>()
.Where(c => c.CustomerId == "ABC")
.Fetch(c => c.Orders)
.ToList();

Rule #2: Don’t fetch multiple collection properties at the same time.
Be careful not to eagerly fetch multiple collection properties at the same time. The following statement will execute a Cartesian product query against the database, so the total number of rows returned will be the total Subordinates times the total orders.

var employees = session
.Query<Employee>()
.Fetch(e => e.Subordinates)
.Fetch(e => e.Orders)
.ToList();

Rule #3: Fetch grandchild collections using FetchMany.
You can fetch grandchild collections too.  The following statement will throw an exception:

var customers = session
.Query<Customer>()
.Fetch(c => c.Orders)
.Fetch(c => c.Orders.OrderLines)
.ToList();

But if you use ‘FetchMany’ and ‘ThenFetchMany’ it will work fine:

var customers = session
.Query<Customer>()
.FetchMany(c => c.Orders)
.ThenFetchMany(o => o.OrderLines)
.ToList();

No comments: