views:

130

answers:

3

I have some objects:

Public Class Person() {
    public int Id {get;set;}
    public IList<Account> Accounts {get;set;}
    public string Email {get; set;}
}

public class Account(){
    public int Id {get;set;}
    public IList<AccountPayment> Payments {get;set;}
    public IList<Venue> Venues {get;set;}
}

public class AccountPayment(){
    public int Id {get;set;}
    public DateTime PaymentDate {get;set;}
    public decimal PaymentAmount {get;set;}
}

public class Venue(){
    public int Id {get;set;}
    public string AddressLine1 {get;set;}
    public string Postcode {get;set;}
}

These classes are mapped to MS Sql with nHibernate - there is a table in the db per class...

I want to create a method in my repository, GetAccounts(int PersonID), that will return a List with all the account's child collections populated in the most efficient way. Can anyone give me any pointers on how to do this - I do not really want to set up the lists as subselects in my mappings if I can help it...

Thanks.

+2  A: 

This blog post explains an efficient way to do that:

http://ayende.com/Blog/archive/2010/01/16/eagerly-loading-entity-associations-efficiently-with-nhibernate.aspx

Diego Mijelshon
Hi Diego, The problem is I am trying to eager load the child collections, of the Account Property of the Person object - I looked at this article before when trying to do this, and on a second investigation, I still can't see a way to do this. Am I missing something?
Paul
+1  A: 

If you have mapped your classes to tables the way you mention, why don't you just call the Person object to get all their accounts? When you call the Person object from your repository, you can eager load Accounts. Like so:

 public Person GetById(int id)
    {
        using (var tx = _sessionBuilder.GetSession().BeginTransaction())
        {
            // -- Lazy load way --
            //Person person = _sessionBuilder.GetSession().Get<Person>(id);
            //tx.Commit();
            //return person;

            // -- Eager load way --                
            Person person = _sessionBuilder.GetSession().CreateCriteria<Person>()
                   .Add(Restrictions.IdEq(id))
                   .SetFetchMode("Accounts", FetchMode.Eager)
                   .UniqueResult<Person>();
            tx.Commit();
            return person;
        }
    }
LordHits
Ideally I would like to eager load the collections on the Accounts property of the person object (Account payment and Venue) too. I don't think the above can achieve this?
Paul
SetFetchMode for collections (especially when there is more than one) it not a good idea performance-wise.
Diego Mijelshon
@Paul - I'm unsure if FetchMode.Eager will do nested collections. You could use NHProf to see the SQL. Another way to eager load that may be to call your repository in your original statement and call Payments and Venues eagerly......SetFetchMode("Payments", FetchMode.Eager).SetFetchMode("Venues", FetchMode.Eager)....
LordHits
@Diego - Performance is the last thing i worry about. :). I'm not sure if Paul's domain set is returning 50 records or 5 million. I'm eager to hear other solutions too. The solution i presented works for me and the application I worked on.
LordHits
Hi, I am using NHProf... It's brilliant. Unfortunately FetchMode.Eager is not having the desired results - I get a massive Cartesian product... starting to think perhaps this can't be done. The annoying thing is, if I set Fetch.Subselect() on the mapping, it's doing exactly what I'm after.
Paul
A: 

Ok, after trying to do this in many different ways, I eventually found that the most efficient solution for me outlined at this question:

http://stackoverflow.com/questions/937388/eager-loading-child-collection-with-nhibernate

My question above was a vastly simplified version of the actual challenge I had, but using the above method managed to get the db hits down to 2... a huge improvement from my initial implementation.

Thanks for your help and pointers guys. Learned a bit along the way...

Paul