Eager loading of lazy loaded entities in nHibernate using ActiveRecord

penderi picture penderi · Dec 19, 2008 · Viewed 8.9k times · Source

I'm working on a project that has a rich object model with various sets of aggregate roots.

We're using the Castle stack (Monorail through to nHibernate with ActiveRecord).

We have marked the aggregate roots as lazy [ActiveRecord(Lazy = true)] and have customized 'eager' routines on our Repository to eager fetch an object graph. We use HQL to define eager fetches from our child collection of our root,

e.g. if Account is the aggregate root (and marked lazy loaded) we'll eager fetch Account .. Order .. Product entities for a complete graph.

So no surprises so far (hopefully).

Now if in the above example, Product is also marked [ActiveRecord(Lazy = true)], this seems to stop the eager fetch directive in the HQL.

Does anyone know a way to force the eager fetch of a lazy loaded child object ??

Cheers ian

Update:

Ok here's some example hql, Using the example from 'me.yahoo.com/../1' below, we're using IMuliQuery to reslove N+1 dependencies when fetching over many-to-many relationships. We're also explicitly using many-to-many mapping classes. As a result our hql is:

from Account a 'm eager loading the graph
inner join fetch a.AccountsOrders ao 
inner join fetch ao.Order
from Account a 'm eager loading the graph
inner join fetch a.AccountAddresses aa
inner join fetch aa.Address ad
where a.ID = ?

... so this executes the 2 sql statements and returns the required minimal rowset, and we can resolve this down into a single object graph. Nice.

But... if, say, Address was marked lazy loaded (and Order wasn't), accessing Order doesn't trigger a further sql statements, yet accessing Address does, despite the fact both are eager loaded.

So why isn't the lazy loaded entity Address, above, eager fetched by the above statement?

Answer

user47393 picture user47393 · Dec 19, 2008

Do an "inner join fetch" on the Account.Order.Product entity. So instead of something like this (which is what you probably already have):

"from Account a inner join fetch a.Order where a.ID = ?"

Tell it to fetch the Order.Product as well:

"from Account a inner join fetch a.Order inner join fetch a.Order.Product where a.ID = ?"