4
votes

I use NHibernate 3.2 with LINQ and have n+1 select queries inq SQL. In mappings fetch set to "join". When I use criteria there's only one select query. Also i can't find method Fetch() or FetchMany() that i saw in different examples. Is there exists any way to solve n+1 problem using Linq to Nhibernate 3.2?
Simplified version of my code

class News
{
    public virtual int Id { get; protected set; }
    public virtual DateTime Date { get; set; }
    public virtual Category Category { get; set; }
}

class Category
{
    public virtual int Id { get; protected set; }
    public virtual ISet<News> News { get; set; }
}

Mappings:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="News" namespace="NewsManagement.Models">
<class name="News" table="News">
<id name="Id">
        <generator class="native" />
</id>
<property name="Date" not-null="true" />
<many-to-one name="Category" fetch="join" column="CategoryId" class="Category, NHibernateManyToOne" not-null="true"/>
</class>
</hibernate-mapping>

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="News" namespace="NewsManagement.Models">
<class name="Category" table="Categories">
    <id name="Id" column="Id">
        <generator class="native" />
    </id>
    <set name="News" fetch="join" cascade="all-delete-orphan">
        <key column="CategoryId" />
        <one-to-many class="News, NHibernateOneToMany" /> 
    </set>
</class>
</hibernate-mapping>

Query that causes many selects:

var news = newsRepository.Linq().Skip(DefaultPageSize*currentPageIndex).Take(DefaultPageSize).OrderByDescending(x => x.Date).ToList();

This is how there is no redundant selects:

var criteria = Session.CreateCriteria<News>();
criteria = criteria.AddOrder(Order.Desc(property));
criteria = criteria.SetMaxResults(pageSize).SetFirstResult((pageNumber - 1)*pageSize);
var news = criteria.List<News>();
2
maybe we can see if you tell us which entity you ar eusing and which query you want to do... - Felice Pollano
@FelicePollano sorry, now code is here - Arсiom Prudnikaŭ

2 Answers

6
votes

Try with this:

criteria.SetFetchMode("Category",FetchMode.Eager);

or with Linq:

session.Query<News>()
                .Fetch(k => k.Category)
                .Skip(n)
                .Take(m)

Or alternatively with QueryOver:

var result = session.QueryOver<News>
                    .Fetch(x => x.Category).Eager
                    .List();
1
votes
var result = session.Query<News>()
                    .Fetch(x => x.Category)
                    .ToList();

^Is this what you're after?

.Query lives in using NHibernate.Linq;.

Alternatively there is QueryOver<T>

Which would look like:

var result = session.QueryOver<News>
                    .Fetch(x => x.Category).Eager
                    .List();