Search code examples
c#nhibernatefetcheager-loadinglinq-to-nhibernate

Eager load child property and grandchildren with NHibernate


I have a class model graph which looks as follows

A { ISet<B> Bset; int Id;}
B { ISet<C> Cset; D Dprop; } 
D { int Id; }

All properties are configured to be lazy loaded. I'm trying to write a query to load all the graph, starting from A. Ideally, it would be something like

var result = (from conf in s.Query<A>()
    .FetchMany(x => x.Bset)
    .ThenFetch(x => x.Dprop)
    // line below doesn't work, because x 
    //is a D object here, and not a "B", as I would like
    .ThenFetchMany(x => x.Cset) 
     where conf.Id == 42
     select conf).SingleOrDefault();

So what I need to do is "go up one level" when I try to fetch the Cset association. Does anybody knows how to do that?

I'm using Nhibernate 4.1.0.


Solution

  • You have to start over with FetchMany.

    var result = (from conf in s.Query<A>()
        .FetchMany(x => x.Bset)
        .ThenFetch(x => x.Dprop)
        .FetchMany(x => x.Bset)
        .ThenFetchMany(x => x.Cset) 
         where conf.Id == 42
         select conf).SingleOrDefault();
    

    But I fear this will cause a Cartesian product, duplicating the results and/or causing bad performances.

    Better switch to lazy-loading. Avoid N+1 select issues by enabling batch loading of lazy loads.

    If you need to close the session then use your entities, you will have to trigger lazy loading by calling NHibernateUtil.Initialize() on their lazily loaded properties, looping on your entities. It will not do anything on those which are already loaded thanks to lazy loading batching.
    An other option is to convert your entities into something like a view model before closing the session.