stiank81
stiank81

Reputation: 25686

Running NHibernate queries without joining

I have Fluent mappings that maps a fictional class Customer to a list of Orders. Now I want to fetch all Customers from the database without loading Orders. Can this be specified somehow in the query/criterion/etc, or is LazyLoading the only solution?

Fictional classes:

public class Customer
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual IList<Order> Orders { get; set; }
}

public class Order
{
    public virtual int Id { get; set; }
    // ++ 
}

Upvotes: 3

Views: 210

Answers (2)

Sunday Ironfoot
Sunday Ironfoot

Reputation: 13050

Lazy loading does this automatically anyway, are you trying to avoid Lazy loading? Why?

For instance:

IList<Customer> customers = _session.CreateCriteria<Customer>().List<Customer>();

Will give you all customers only. Orders will only be fetched from the database when you call the Order collection on a Customer entity eg:

foreach(Customer customer in customers)
{
    IList<Order> orders = customer.Orders; // Will hit the database
}

So if you have 10 Customers, this code will hit the database 11 times (1 to get the Customer, 10 to retrieve Orders for each Customer). This gives you a SELECT N+1 problem, though if you're not interested in the Orders for each customer, then simply don't call Orders and they won't be fetched. I don't mean to be rude, but this seems fairly obvious, am I misunderstanding your question?


Update: In response to the comments. You should consider using a Report Query if sending your POCO's over a web service, because your POCO's would loose their attachment to your NHibernate Session object, and thus lazy loading won't work (Orders collection will just return NULL). In other words the 'thing' calling your web service properly isn't going to know anything about NHibernate, or your domain model, so:

public IList<CustomerView> GetAllCustomers()
{
    return (from c in _session.Query<Customer>()
            select new CustomerView()
            {
                Id = c.Id,
                Name = c.Name
            }).ToList();
}

public CustomerDetail GetCustomerFromId(int id)
{
    return (from c in _session.Query<Customer>()
            where c.Id == id
            select new CustomerDetail()
            {
                Id = c.Id,
                Name = c.Name
                FullAddress = c.FormatFullAddress(),
                Orders = c.Orders,
                // other properties (snip)
            }).SingleOrDefault();
}

This is using the LINQ provider built into NHibernate 3.0, if you're not using NHibernate 3.0, and can do report queries using Projections. The syntax escapes me so try here http://nhibernate.info/doc/nh/en/index.html#querycriteria-projection

Upvotes: 2

Frederik Gheysels
Frederik Gheysels

Reputation: 56934

You can specify the FetchMode in the Criteria:

var crit = session.CreateCriteria (typeof(SomeObject));
crit.SetFetchMode ("association", FetchMode.Eager);

You can also specify in the mapping that an association/collection should not be lazy loaded as well. The default is that collections are lazy loaded.

Upvotes: 1

Related Questions