20

I was looking at this

Be careful not to eagerly fetch multiple collection properties at the same time. Although this statement will work fine:

var employees = session.Query() .Fetch(e => e.Subordinates) .Fetch(e => e.Orders).ToList();

I need to fetch 2 references so I would need to do something like that. Is there a better way of doing this.

I can't do .ThenFetchMany() as it goes to the into the child objects but the ones I am after on the same level.

harriyott
  • 10,505
  • 10
  • 64
  • 103
chobo2
  • 83,322
  • 195
  • 530
  • 832

1 Answers1

32

Well, the query will still return the results you want, but as stated, it will return a cartesian product, i.e. the SQL query will return count(e.Subordinates) * count(e.Orders) results, which could add up pretty quickly, especially if you have more than just two collections.

NHibernate introduced Futures with the 2.1 release. Unfortunately there seems to be no way in the current NHibernate 3.0 release to make them work with NHibernate.Linq (session.Query<T>()).

Futures allow you to perform multiple queries in one roundtrip to the database (as long as the DB supports it, but most do). In that case you will only have count(e.Subordinates) + count(e.Orders) results, which is obviously the minimum.

Futures work with the criteria API, HQL and they are supposed to work with the new QueryOver API (I have not tested that, yet).

NHibernate.Linq does have Query().ToFuture() and Query().ToFutureValue(), but so far I only get Exceptions when I use them.

Edit:

I just checked again for the Linq API and it seems as if it is working if you do not use Fetch. The following will result in three SQL queries that are executed in one roundtrip. The total number of rows return will be 1 + count(Subordinates) + count(Orders).

int id = 1;

// get the Employee with the id defined above
var employee = repo.Session.Query<Employee>()
    .Where(o => o.Id == id)
    .ToFuture<Employee>();

// get the Subordinates (these are other employees?)
var subordinates = repo.Session.Query<Employee>()
    .Where(o => o.HeadEmployee.Id == id)
    .ToFuture<Employee>();

// get the Orders for the employee
var orders = repo.Session.Query<Order>()
    .Where(o => o.Employee.Id == id)
    .ToFuture<Order>();

// execute all three queries in one roundtrip
var list = employee.ToList();
// get the first (and only) Employee in the list, NHibernate will have populated the Subordinates and Orders
Employee empl = list.FirstOrDefault();

Thank you for having marked this as the answer anyway.

Florian Lim
  • 5,332
  • 2
  • 27
  • 28
  • Hmm I guess I will have to wait till they make it for linq then. I am using only 2 collections right now so I should be fine till they bring it out(I really am not crazy about the other ways). – chobo2 Mar 15 '11 at 23:14
  • @chobo2 I edited my answer and provided a possible, working solution for NHibernate.Linq – Florian Lim Mar 15 '11 at 23:57
  • If I could +1 this twice I would. This just saved me. *thank you*. – Tin Can Jan 06 '12 at 19:32
  • @FlorianLim - Why do you keep referring to `NHibernate.Linq` which is un-related to the code supplied? `NHibernate.Linq` and the `Query` API are not the same thing. The Linq provider was written for 2.1 and should NOT be used with 3.# since 3.# ships with its own built in Linq provider. – Phill Jun 12 '13 at 14:24
  • 1
    @Phill To be honest, I don't really know. My last reply to this was more than two years ago, so it might very well be that I used the wrong terminology and said "NHibernate.Linq" when I meant the built in Linq provider (perhaps because it was the same namespace, wasn't it?). Anyway, I never really used it, since I prefer the QueryOver API. – Florian Lim Jun 13 '13 at 12:31
  • @Phill I'm using NH 3.3.2 and the `Query` method is in the `NHibernate.Linq` namespace (within the `LinqExtensionMethods` static class.) – Merenzo Jun 25 '13 at 05:46
  • @Merenzo - yes but the way it's written is confusing. 'to make them work with NHibernate.Linq' & 'NHibernate.Linq does have Query().ToFuture()...' both sound like its referring to the 2.# LINQ Provider. Which is incorrect since it's referring to the LINQ API not the LINQ Provider. Hense why I was asking Florian. – Phill Jun 25 '13 at 06:06
  • One problem is (for me) one of my collections doesn't have the ParentID as a class property - so I can't use this. That is, my "ParentID" for the collection is mapped, using NHibernate, but I don't need it as a class property, in C#, so I don't have it. But now I can't say Where(child.ParentID == id) so I can't use Future fetch queries, it seems. – PandaWood Aug 05 '15 at 01:24