Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this the right way of using ThenFetch() to load multiple collections?

I'm trying to load all the collections eagerly, using NHibernate 3 alpha 1. I'm wondering if this the right way of using ThenFetch()?

Properties with plural names are collections. The others are just a single object.

            IQueryable<T> milestoneInstances = Db.Find<T, IQueryable<T>>(db =>
            from mi in db
            where mi.RunDate == runDate
            select mi).Fetch(mi => mi.Milestone)
                .ThenFetch(m => m.PrimaryOwners)
                .Fetch(mi => mi.Milestone)
                .ThenFetch(m => m.SecondaryOwners)
                .Fetch(mi => mi.Milestone)
                .ThenFetch(m => m.Predecessors)
                .Fetch(mi => mi.Milestone)
                .ThenFetch(m => m.Function)
                .Fetch(mi => mi.Milestone)
                .ThenFetchMany(m => m.Jobs)
                .ThenFetch(j => j.Source)
                ;

I thought of asking this in the NHibernate forums but unfortunately access to google groups is forbidden from where I am. I know Fabio is here, so maybe the guys from the NHibernate team can shed some light on this? Thanks

like image 396
esegura Avatar asked Aug 03 '10 15:08

esegura


3 Answers

Apparently, there's no "right" way to use ThenFetch in such a case. Your example works fine but SQL produced contains many joins to Milestone, which isn't that right.

Using IQueryOver instead of IQueryable allows you to use complex syntax in Fetch:

Fetch(p => p.B) 
Fetch(p => p.B.C) // if B is not a collection ... or 
Fetch(p => p.B[0].C) // if B is a collection ... or 
Fetch(p => p.B.First().C) // if B is an IEnumerable (using .First() extension method) 

So in your case it would be:

query // = session.QueryOver<X>()
    .Fetch(mi => mi.Milestone).Eager
    .Fetch(mi => mi.Milestone.PrimaryOwners).Eager
    .Fetch(mi => mi.Milestone.SecondaryOwners).Eager
    .Fetch(mi => mi.Milestone.Predecessors).Eager
    .Fetch(mi => mi.Milestone.Function).Eager
    .Fetch(mi => mi.Milestone.Jobs).Eager
    .Fetch(mi => mi.Milestone.Jobs.First().Source).Eager
like image 173
foka Avatar answered Nov 13 '22 19:11

foka


The one thing you are missing is that you should use FetchMany() and ThenFetchMany() is the child property is a collection.

like image 31
leora Avatar answered Nov 13 '22 19:11

leora


        IQueryable<T> milestoneInstances = Db.Find<T, IQueryable<T>>(db =>
        from mi in db
        where mi.RunDate == runDate
        select mi);

var fetch = milestoneInstances.Fetch(f => f.Milestone);
fetch.ThenFetch(f => f.PrimaryOwners);
fetch.ThenFetch(f => f.SecondaryOwners);
//...
like image 30
Jason Sylvestre Avatar answered Nov 13 '22 20:11

Jason Sylvestre