14

I'm using NHibernate 3.0 with both the LINQ provider and QueryOver. Sometimes I want to eager load related data, and there comes the method "Fetch" to the rescue, both in LINQ and QueryOver. Now I have a special scenario where I want to eager load a property not directly on the second level, like:

Foo f = ...;
f.A.B.C

with LINQ there's no problem, as you can "chain" fetches with the method "ThenFetch", like:

var result = Session.Query<Foo>().Fetch(a => a.A).ThenFetch(b => b.B).ThenFetch(c => c.C).ToList();

In QueryOver there's no such method, so how can I achieve the same result?

Thanks in advance.

psousa
  • 6,676
  • 1
  • 32
  • 44

3 Answers3

16

I actually managed to solve this problem using two different approaches:

Approach one:

Session.QueryOver<Foo>().Fetch(x => x.A).Fetch(x => x.A.B).Fetch(x => x.A.B.C)

Approach two:

A a = null;
B b = null;
C c = null;

Session.QueryOver<Foo>()
    .JoinAlias(x => x.A, () => a)
    .JoinAlias(() => a.B, () => b)
    .JoinAlias(() => b.C, () => c)

Both work (altough I'm not exactly sure if one of them generated "inner" and the other one "outer" joins).

psousa
  • 6,676
  • 1
  • 32
  • 44
  • Approach two seems to only work for One to One, it fails on collections. – Phill Apr 12 '11 at 06:51
  • 5
    I take that back, it does work if you specify the join type for the collection, by default it attempts an inner join. If you specify a left outer join it works perfectly. – Phill Apr 12 '11 at 07:10
  • Isn't the FetchType (Eager, Lazy, Default) needed after Fetch()? – Andreas H. Mar 13 '12 at 10:10
  • Nope. At least it wasn't when I posted this answer (with NH 3.0) – psousa Mar 13 '12 at 15:21
  • While this answer is correct, in my own case I was specifically looking to fetch the child of a *collection* or *list*. For this case, @xanatos points out that you simply need to access the first element of the collection/list in order to make the C# compiler happy: `query .Fetch(x => x.SomeEnumerable) .Fetch(x => x.SomeEnumerable.First().SomeProperty)` When NHibernate actually examines this lambda expression, it ignores the call to `.First()` and simply looks at the property chain. Realizing this made a huge difference for me. – adamjcooper Oct 09 '12 at 07:41
16

Just as a curiosity, I'll post the reply they gave me on the NHibernate Jira:

query 
    .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) 
xanatos
  • 109,618
  • 12
  • 197
  • 280
4

I think you can do that with JoinQueryOver

IQueryOver<Relation> actual =
   CreateTestQueryOver<Relation>()
    .Inner.JoinQueryOver(r => r.Related1)
    .Left.JoinQueryOver(r => r.Related2)
    .Right.JoinQueryOver(r => r.Related3)
    .Full.JoinQueryOver(r => r.Related4)
    .JoinQueryOver(r => r.Collection1, () => collection1Alias)
    .Left.JoinQueryOver(r => r.Collection2, () => collection2Alias)
    .Right.JoinQueryOver(r => r.Collection3)
    .Full.JoinQueryOver(r => r.People, () => personAlias); 
Bas
  • 678
  • 6
  • 10