Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Eager Fetching with nhibernate Criteria API

I am trying to use the criteria Api over multiple tables with eager loading.

My stripped-down Entities look like this:

class Limit
{
    Risk {get; set;}
}

class Risk
{
   List<Company> Companies { get;set;}
}

class Company
{
  List<Address> OldAdresses {get;set;}
}

class Address
{
  string Street { get;set;}
}

My Criteria call looks like this:

var CriterionGruppe = Expression.Eq("Account.Id", someGuid);

var temp = _transaktion.Session.CreateCriteria(typeof(Limit))
.SetFetchMode("Risk", FetchMode.Eager)
.SetFetchMode("Risk.Companies", FetchMode.Eager)
.Add(CriterionGruppe)
.SetResultTransformer(new DistinctRootEntityResultTransformer())
.List<Limit>();

The addresses are still loaded with many Selects. How can I include the old adresses of a Company in my criteria call.

I already read a blog entry in ayende's blog and several other question here at stackoverflow. But still had no luck.

I hope someone could point me in the right direction.

Thanks in advance peter

When must we use eager loading in NHibernate? What is it's usage?

NHibernate Eager Fetching Over Multiple Levels

Ayende Blog

like image 558
user631833 Avatar asked Jan 11 '12 13:01

user631833


People also ask

What is criteria NHibernate?

The NHibernate Query by Criteria API lets you build a query by manipulating criteria objects at runtime. This approach lets you specify constraints dynamically without direct string manipulations, but it doesn't lose much of the flexibility or power of HQL.

What is projection in NHibernate?

The "projection" is kind of like plucking out what data you will need so that NHibernate only asks the database for just that data when it makes the SQL.


1 Answers

var account = _transaktion.Session.Load<Account>(someGuid);
var temp = _transaktion.Session.CreateCriteria(typeof(Limit))
    .SetFetchMode("Risk", FetchMode.Eager)
    .SetFetchMode("Risk.Companies", FetchMode.Eager)
    .SetFetchMode("Company.OldAddresses", FetchMode.Eager)
    .Add(Expression.Eq("Account", account))
    .SetResultTransformer(new DistinctRootEntityResultTransformer())
    .List<Limit>();

However this is very inefficient. You are loading a massive amount of duplicate data to make 1 sql query. A better approach would be

  1. load a projection of what is actually needed
  2. use Futures and Batched lazy loading to avoid a single cartesian result set and select n+1.
like image 113
Jason Meckley Avatar answered Oct 01 '22 10:10

Jason Meckley