Search code examples
c#nhibernatefluent-nhibernatequeryover

Why is nHibernate lazy loading and ignoring the results of a future query?


I have a method that retrieves an Entity from a database using nHibernate. It's quite a complex Entity:

Level4 has many Level3s which have many Level2s which have many Level1s which has a Level1Ref

So I use a few futures like this:

        var future = this.Session.QueryOver<Level4>()
            .Where(x => x.Id == level4Id)
            .Fetch(x => x.Level3List).Eager
            .Fetch(x => x.Level3List.First().Level2List).Eager
            .Left.JoinAlias(x => x.Level3List, () => level3Alias, x => x.AnotherThing.Id == anotherThingId)
            .FutureValue();

And some queries like this:

        this.Session.QueryOver<Level1>()
            .Fetch(x => x).Eager
            .Fetch(x => x.Level1Ref).Eager
            .Fetch(x => x.Level2).Eager
            .Inner.JoinAlias(x => x.Level2, () => level2Alias)
            .Inner.JoinAlias(() => level2Alias.Level3, () => level3Alias, x => x.AnotherThing.Id == anotherThingId && level3Alias.Level4.Id == level4Id)
            .Future();

And then:

var record = future.Value;

This all generates the SQL that I would expect but when I try to iterate over the Level2.Level1List it lazy loads the records in that list.

The Question:

This is the problem. What have I? done wrong in my query that nHibernate thinks it needs to go to the database for information that it has already got? (I've got a hunch that I need to swap some of my JoinQueryOver bits for eager fetches?

(Questions edited to simplify examples)


Solution

  • After lots of investigation the only way I could get this working was change all of my queries so they have the same TRoot. Ie. Change them so they all start like this:

    this.Session.QueryOver<Level4>()
    

    This obviously isn't ideal in situations like this:

    FishMonger

    Collection of Fish

    Collection of Eye Collection of Bone

    It means I have to write two queries and join in Fish twice...

    The alternative is to lazy load and batch the queries but the requirement is to make only one round trip to the database.